• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- DNBBreakpoint.cpp ---------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  Created by Greg Clayton on 6/29/07.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "DNBBreakpoint.h"
14 #include "DNBLog.h"
15 #include "MachProcess.h"
16 #include <algorithm>
17 #include <assert.h>
18 #include <inttypes.h>
19 
20 #pragma mark-- DNBBreakpoint
DNBBreakpoint(nub_addr_t addr,nub_size_t byte_size,bool hardware)21 DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size,
22                              bool hardware)
23     : m_retain_count(1), m_byte_size(static_cast<uint32_t>(byte_size)),
24       m_opcode(), m_addr(addr), m_enabled(0), m_hw_preferred(hardware),
25       m_is_watchpoint(0), m_watch_read(0), m_watch_write(0),
26       m_hw_index(INVALID_NUB_HW_INDEX) {}
27 
~DNBBreakpoint()28 DNBBreakpoint::~DNBBreakpoint() {}
29 
Dump() const30 void DNBBreakpoint::Dump() const {
31   if (IsBreakpoint()) {
32     DNBLog("DNBBreakpoint addr = 0x%llx  state = %s  type = %s breakpoint  "
33            "hw_index = %i",
34            (uint64_t)m_addr, m_enabled ? "enabled " : "disabled",
35            IsHardware() ? "hardware" : "software", GetHardwareIndex());
36   } else {
37     DNBLog("DNBBreakpoint addr = 0x%llx  size = %llu  state = %s  type = %s "
38            "watchpoint (%s%s)  hw_index = %i",
39            (uint64_t)m_addr, (uint64_t)m_byte_size,
40            m_enabled ? "enabled " : "disabled",
41            IsHardware() ? "hardware" : "software", m_watch_read ? "r" : "",
42            m_watch_write ? "w" : "", GetHardwareIndex());
43   }
44 }
45 
46 #pragma mark-- DNBBreakpointList
47 
DNBBreakpointList()48 DNBBreakpointList::DNBBreakpointList() {}
49 
~DNBBreakpointList()50 DNBBreakpointList::~DNBBreakpointList() {}
51 
Add(nub_addr_t addr,nub_size_t length,bool hardware)52 DNBBreakpoint *DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length,
53                                       bool hardware) {
54   m_breakpoints.insert(
55       std::make_pair(addr, DNBBreakpoint(addr, length, hardware)));
56   iterator pos = m_breakpoints.find(addr);
57   return &pos->second;
58 }
59 
Remove(nub_addr_t addr)60 bool DNBBreakpointList::Remove(nub_addr_t addr) {
61   iterator pos = m_breakpoints.find(addr);
62   if (pos != m_breakpoints.end()) {
63     m_breakpoints.erase(pos);
64     return true;
65   }
66   return false;
67 }
68 
FindByAddress(nub_addr_t addr)69 DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) {
70   iterator pos = m_breakpoints.find(addr);
71   if (pos != m_breakpoints.end())
72     return &pos->second;
73 
74   return NULL;
75 }
76 
FindByAddress(nub_addr_t addr) const77 const DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) const {
78   const_iterator pos = m_breakpoints.find(addr);
79   if (pos != m_breakpoints.end())
80     return &pos->second;
81 
82   return NULL;
83 }
84 
85 // Finds the next breakpoint at an address greater than or equal to "addr"
FindBreakpointsThatOverlapRange(nub_addr_t addr,nub_addr_t size,std::vector<DNBBreakpoint * > & bps)86 size_t DNBBreakpointList::FindBreakpointsThatOverlapRange(
87     nub_addr_t addr, nub_addr_t size, std::vector<DNBBreakpoint *> &bps) {
88   bps.clear();
89   iterator end = m_breakpoints.end();
90   // Find the first breakpoint with an address >= to "addr"
91   iterator pos = m_breakpoints.lower_bound(addr);
92   if (pos != end) {
93     if (pos != m_breakpoints.begin()) {
94       // Watch out for a breakpoint at an address less than "addr" that might
95       // still overlap
96       iterator prev_pos = pos;
97       --prev_pos;
98       if (prev_pos->second.IntersectsRange(addr, size, NULL, NULL, NULL))
99         bps.push_back(&pos->second);
100     }
101 
102     while (pos != end) {
103       // When we hit a breakpoint whose start address is greater than "addr +
104       // size" we are done.
105       // Do the math in a way that doesn't risk unsigned overflow with bad
106       // input.
107       if ((pos->second.Address() - addr) >= size)
108         break;
109 
110       // Check if this breakpoint overlaps, and if it does, add it to the list
111       if (pos->second.IntersectsRange(addr, size, NULL, NULL, NULL)) {
112         bps.push_back(&pos->second);
113         ++pos;
114       }
115     }
116   }
117   return bps.size();
118 }
119 
Dump() const120 void DNBBreakpointList::Dump() const {
121   const_iterator pos;
122   const_iterator end = m_breakpoints.end();
123   for (pos = m_breakpoints.begin(); pos != end; ++pos)
124     pos->second.Dump();
125 }
126 
DisableAll()127 void DNBBreakpointList::DisableAll() {
128   iterator pos, end = m_breakpoints.end();
129   for (pos = m_breakpoints.begin(); pos != end; ++pos)
130     pos->second.SetEnabled(false);
131 }
132 
RemoveTrapsFromBuffer(nub_addr_t addr,nub_size_t size,void * p) const133 void DNBBreakpointList::RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size,
134                                               void *p) const {
135   uint8_t *buf = (uint8_t *)p;
136   const_iterator end = m_breakpoints.end();
137   const_iterator pos = m_breakpoints.lower_bound(addr);
138   while (pos != end && (pos->first < (addr + size))) {
139     nub_addr_t intersect_addr;
140     nub_size_t intersect_size;
141     nub_size_t opcode_offset;
142     const DNBBreakpoint &bp = pos->second;
143     if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size,
144                            &opcode_offset)) {
145       assert(addr <= intersect_addr && intersect_addr < addr + size);
146       assert(addr < intersect_addr + intersect_size &&
147              intersect_addr + intersect_size <= addr + size);
148       assert(opcode_offset + intersect_size <= bp.ByteSize());
149       nub_size_t buf_offset = intersect_addr - addr;
150       ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset,
151                intersect_size);
152     }
153     ++pos;
154   }
155 }
156 
DisableAllBreakpoints(MachProcess * process)157 void DNBBreakpointList::DisableAllBreakpoints(MachProcess *process) {
158   iterator pos, end = m_breakpoints.end();
159   for (pos = m_breakpoints.begin(); pos != end; ++pos)
160     process->DisableBreakpoint(pos->second.Address(), false);
161 }
162 
DisableAllWatchpoints(MachProcess * process)163 void DNBBreakpointList::DisableAllWatchpoints(MachProcess *process) {
164   iterator pos, end = m_breakpoints.end();
165   for (pos = m_breakpoints.begin(); pos != end; ++pos)
166     process->DisableWatchpoint(pos->second.Address(), false);
167 }
168 
RemoveDisabled()169 void DNBBreakpointList::RemoveDisabled() {
170   iterator pos = m_breakpoints.begin();
171   while (pos != m_breakpoints.end()) {
172     if (!pos->second.IsEnabled())
173       pos = m_breakpoints.erase(pos);
174     else
175       ++pos;
176   }
177 }
178