1 //===-- DNBBreakpoint.h -----------------------------------------*- 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 #ifndef __DNBBreakpoint_h__
15 #define __DNBBreakpoint_h__
16 
17 #include <mach/mach.h>
18 
19 #include <map>
20 #include <vector>
21 
22 #include "DNBDefs.h"
23 
24 class MachProcess;
25 
26 class DNBBreakpoint {
27 public:
28   DNBBreakpoint(nub_addr_t m_addr, nub_size_t byte_size, bool hardware);
29   ~DNBBreakpoint();
30 
31   nub_size_t ByteSize() const { return m_byte_size; }
32   uint8_t *SavedOpcodeBytes() { return &m_opcode[0]; }
33   const uint8_t *SavedOpcodeBytes() const { return &m_opcode[0]; }
34   nub_addr_t Address() const { return m_addr; }
35   //    nub_thread_t ThreadID() const { return m_tid; }
36   bool IsEnabled() const { return m_enabled; }
37   bool IntersectsRange(nub_addr_t addr, nub_size_t size,
38                        nub_addr_t *intersect_addr, nub_size_t *intersect_size,
39                        nub_size_t *opcode_offset) const {
40     // We only use software traps for software breakpoints
41     if (IsBreakpoint() && IsEnabled() && !IsHardware()) {
42       if (m_byte_size > 0) {
43         const nub_addr_t bp_end_addr = m_addr + m_byte_size;
44         const nub_addr_t end_addr = addr + size;
45         // Is the breakpoint end address before the passed in start address?
46         if (bp_end_addr <= addr)
47           return false;
48         // Is the breakpoint start address after passed in end address?
49         if (end_addr <= m_addr)
50           return false;
51         if (intersect_addr || intersect_size || opcode_offset) {
52           if (m_addr < addr) {
53             if (intersect_addr)
54               *intersect_addr = addr;
55             if (intersect_size)
56               *intersect_size =
57                   std::min<nub_addr_t>(bp_end_addr, end_addr) - addr;
58             if (opcode_offset)
59               *opcode_offset = addr - m_addr;
60           } else {
61             if (intersect_addr)
62               *intersect_addr = m_addr;
63             if (intersect_size)
64               *intersect_size =
65                   std::min<nub_addr_t>(bp_end_addr, end_addr) - m_addr;
66             if (opcode_offset)
67               *opcode_offset = 0;
68           }
69         }
70         return true;
71       }
72     }
73     return false;
74   }
75   void SetEnabled(bool enabled) {
76     if (!enabled)
77       SetHardwareIndex(INVALID_NUB_HW_INDEX);
78     m_enabled = enabled;
79   }
80   void SetIsWatchpoint(uint32_t type) {
81     m_is_watchpoint = 1;
82     m_watch_read = (type & WATCH_TYPE_READ) != 0;
83     m_watch_write = (type & WATCH_TYPE_WRITE) != 0;
84   }
85   bool IsBreakpoint() const { return m_is_watchpoint == 0; }
86   bool IsWatchpoint() const { return m_is_watchpoint == 1; }
87   bool WatchpointRead() const { return m_watch_read != 0; }
88   bool WatchpointWrite() const { return m_watch_write != 0; }
89   bool HardwarePreferred() const { return m_hw_preferred; }
90   bool IsHardware() const { return m_hw_index != INVALID_NUB_HW_INDEX; }
91   uint32_t GetHardwareIndex() const { return m_hw_index; }
92   void SetHardwareIndex(uint32_t hw_index) { m_hw_index = hw_index; }
93   void Dump() const;
94   uint32_t Retain() { return ++m_retain_count; }
95   uint32_t Release() {
96     if (m_retain_count == 0)
97       return 0;
98     return --m_retain_count;
99   }
100 
101 private:
102   uint32_t m_retain_count; // Each breakpoint is maintained by address and is
103                            // ref counted in case multiple people set a
104                            // breakpoint at the same address
105   uint32_t m_byte_size;    // Length in bytes of the breakpoint if set in memory
106   uint8_t m_opcode[8];     // Saved opcode bytes
107   nub_addr_t m_addr;       // Address of this breakpoint
108   uint32_t m_enabled : 1,  // Flags for this breakpoint
109       m_hw_preferred : 1,  // 1 if this point has been requested to be set using
110                            // hardware (which may fail due to lack of resources)
111       m_is_watchpoint : 1, // 1 if this is a watchpoint
112       m_watch_read : 1,    // 1 if we stop when the watched data is read from
113       m_watch_write : 1;   // 1 if we stop when the watched data is written to
114   uint32_t
115       m_hw_index; // The hardware resource index for this breakpoint/watchpoint
116 };
117 
118 class DNBBreakpointList {
119 public:
120   DNBBreakpointList();
121   ~DNBBreakpointList();
122 
123   DNBBreakpoint *Add(nub_addr_t addr, nub_size_t length, bool hardware);
124   bool Remove(nub_addr_t addr);
125   DNBBreakpoint *FindByAddress(nub_addr_t addr);
126   const DNBBreakpoint *FindByAddress(nub_addr_t addr) const;
127 
128   size_t FindBreakpointsThatOverlapRange(nub_addr_t addr, nub_addr_t size,
129                                          std::vector<DNBBreakpoint *> &bps);
130 
131   void Dump() const;
132 
133   size_t Size() const { return m_breakpoints.size(); }
134   void DisableAll();
135 
136   void RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size, void *buf) const;
137 
138   void DisableAllBreakpoints(MachProcess *process);
139   void DisableAllWatchpoints(MachProcess *process);
140   void RemoveDisabled();
141 
142 protected:
143   typedef std::map<nub_addr_t, DNBBreakpoint> collection;
144   typedef collection::iterator iterator;
145   typedef collection::const_iterator const_iterator;
146   collection m_breakpoints;
147 };
148 
149 #endif
150