1254721Semaste//===-- BreakpointLocationList.cpp ------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#include "lldb/Breakpoint/BreakpointLocationList.h"
10258884Semaste
11314564Sdim#include "lldb/Breakpoint/Breakpoint.h"
12254721Semaste#include "lldb/Breakpoint/BreakpointLocation.h"
13258884Semaste#include "lldb/Core/Module.h"
14254721Semaste#include "lldb/Core/Section.h"
15262528Semaste#include "lldb/Target/SectionLoadList.h"
16254721Semaste#include "lldb/Target/Target.h"
17327952Sdim#include "lldb/Utility/ArchSpec.h"
18254721Semaste
19254721Semasteusing namespace lldb;
20254721Semasteusing namespace lldb_private;
21254721Semaste
22309124SdimBreakpointLocationList::BreakpointLocationList(Breakpoint &owner)
23314564Sdim    : m_owner(owner), m_locations(), m_address_to_location(), m_mutex(),
24314564Sdim      m_next_id(0), m_new_location_recorder(nullptr) {}
25254721Semaste
26296417SdimBreakpointLocationList::~BreakpointLocationList() = default;
27254721Semaste
28254721SemasteBreakpointLocationSP
29314564SdimBreakpointLocationList::Create(const Address &addr,
30314564Sdim                               bool resolve_indirect_symbols) {
31314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
32314564Sdim  // The location ID is just the size of the location list + 1
33314564Sdim  lldb::break_id_t bp_loc_id = ++m_next_id;
34314564Sdim  BreakpointLocationSP bp_loc_sp(
35314564Sdim      new BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID,
36314564Sdim                             m_owner.IsHardware(), resolve_indirect_symbols));
37314564Sdim  m_locations.push_back(bp_loc_sp);
38314564Sdim  m_address_to_location[addr] = bp_loc_sp;
39314564Sdim  return bp_loc_sp;
40254721Semaste}
41254721Semaste
42314564Sdimbool BreakpointLocationList::ShouldStop(StoppointCallbackContext *context,
43314564Sdim                                        lldb::break_id_t break_id) {
44314564Sdim  BreakpointLocationSP bp = FindByID(break_id);
45314564Sdim  if (bp) {
46314564Sdim    // Let the BreakpointLocation decide if it should stop here (could not have
47341825Sdim    // reached it's target hit count yet, or it could have a callback that
48341825Sdim    // decided it shouldn't stop (shared library loads/unloads).
49314564Sdim    return bp->ShouldStop(context);
50314564Sdim  }
51341825Sdim  // We should stop here since this BreakpointLocation isn't valid anymore or
52341825Sdim  // it doesn't exist.
53314564Sdim  return true;
54254721Semaste}
55254721Semaste
56314564Sdimlldb::break_id_t BreakpointLocationList::FindIDByAddress(const Address &addr) {
57314564Sdim  BreakpointLocationSP bp_loc_sp = FindByAddress(addr);
58314564Sdim  if (bp_loc_sp) {
59314564Sdim    return bp_loc_sp->GetID();
60314564Sdim  }
61314564Sdim  return LLDB_INVALID_BREAK_ID;
62254721Semaste}
63254721Semaste
64314564Sdimstatic bool Compare(BreakpointLocationSP lhs, lldb::break_id_t val) {
65314564Sdim  return lhs->GetID() < val;
66258884Semaste}
67258884Semaste
68254721SemasteBreakpointLocationSP
69314564SdimBreakpointLocationList::FindByID(lldb::break_id_t break_id) const {
70314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
71314564Sdim  collection::const_iterator end = m_locations.end();
72314564Sdim  collection::const_iterator pos =
73314564Sdim      std::lower_bound(m_locations.begin(), end, break_id, Compare);
74314564Sdim  if (pos != end && (*pos)->GetID() == break_id)
75314564Sdim    return *(pos);
76314564Sdim  else
77314564Sdim    return BreakpointLocationSP();
78254721Semaste}
79254721Semaste
80314564Sdimsize_t BreakpointLocationList::FindInModule(
81314564Sdim    Module *module, BreakpointLocationCollection &bp_loc_list) {
82314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
83314564Sdim  const size_t orig_size = bp_loc_list.GetSize();
84314564Sdim  collection::iterator pos, end = m_locations.end();
85254721Semaste
86314564Sdim  for (pos = m_locations.begin(); pos != end; ++pos) {
87314564Sdim    BreakpointLocationSP break_loc = (*pos);
88314564Sdim    SectionSP section_sp(break_loc->GetAddress().GetSection());
89314564Sdim    if (section_sp && section_sp->GetModule().get() == module) {
90314564Sdim      bp_loc_list.Add(break_loc);
91254721Semaste    }
92314564Sdim  }
93314564Sdim  return bp_loc_list.GetSize() - orig_size;
94254721Semaste}
95254721Semaste
96254721Semasteconst BreakpointLocationSP
97314564SdimBreakpointLocationList::FindByAddress(const Address &addr) const {
98314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
99314564Sdim  BreakpointLocationSP bp_loc_sp;
100314564Sdim  if (!m_locations.empty()) {
101314564Sdim    Address so_addr;
102254721Semaste
103314564Sdim    if (addr.IsSectionOffset()) {
104314564Sdim      so_addr = addr;
105314564Sdim    } else {
106314564Sdim      // Try and resolve as a load address if possible.
107314564Sdim      m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress(
108314564Sdim          addr.GetOffset(), so_addr);
109314564Sdim      if (!so_addr.IsValid()) {
110314564Sdim        // The address didn't resolve, so just set to passed in addr.
111314564Sdim        so_addr = addr;
112314564Sdim      }
113254721Semaste    }
114254721Semaste
115314564Sdim    addr_map::const_iterator pos = m_address_to_location.find(so_addr);
116314564Sdim    if (pos != m_address_to_location.end())
117314564Sdim      bp_loc_sp = pos->second;
118314564Sdim  }
119314564Sdim
120314564Sdim  return bp_loc_sp;
121254721Semaste}
122254721Semaste
123314564Sdimvoid BreakpointLocationList::Dump(Stream *s) const {
124314564Sdim  s->Printf("%p: ", static_cast<const void *>(this));
125314564Sdim  // s->Indent();
126314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
127314564Sdim  s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n",
128314564Sdim            (uint64_t)m_locations.size());
129314564Sdim  s->IndentMore();
130314564Sdim  collection::const_iterator pos, end = m_locations.end();
131314564Sdim  for (pos = m_locations.begin(); pos != end; ++pos)
132353358Sdim    (*pos)->Dump(s);
133314564Sdim  s->IndentLess();
134254721Semaste}
135254721Semaste
136314564SdimBreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) {
137314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
138314564Sdim  BreakpointLocationSP bp_loc_sp;
139314564Sdim  if (i < m_locations.size())
140314564Sdim    bp_loc_sp = m_locations[i];
141254721Semaste
142314564Sdim  return bp_loc_sp;
143254721Semaste}
144254721Semaste
145314564Sdimconst BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) const {
146314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
147314564Sdim  BreakpointLocationSP bp_loc_sp;
148314564Sdim  if (i < m_locations.size())
149314564Sdim    bp_loc_sp = m_locations[i];
150254721Semaste
151314564Sdim  return bp_loc_sp;
152254721Semaste}
153254721Semaste
154314564Sdimvoid BreakpointLocationList::ClearAllBreakpointSites() {
155314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
156314564Sdim  collection::iterator pos, end = m_locations.end();
157314564Sdim  for (pos = m_locations.begin(); pos != end; ++pos)
158314564Sdim    (*pos)->ClearBreakpointSite();
159254721Semaste}
160254721Semaste
161314564Sdimvoid BreakpointLocationList::ResolveAllBreakpointSites() {
162314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
163314564Sdim  collection::iterator pos, end = m_locations.end();
164254721Semaste
165314564Sdim  for (pos = m_locations.begin(); pos != end; ++pos) {
166314564Sdim    if ((*pos)->IsEnabled())
167314564Sdim      (*pos)->ResolveBreakpointSite();
168314564Sdim  }
169254721Semaste}
170254721Semaste
171314564Sdimuint32_t BreakpointLocationList::GetHitCount() const {
172314564Sdim  uint32_t hit_count = 0;
173314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
174314564Sdim  collection::const_iterator pos, end = m_locations.end();
175314564Sdim  for (pos = m_locations.begin(); pos != end; ++pos)
176314564Sdim    hit_count += (*pos)->GetHitCount();
177314564Sdim  return hit_count;
178254721Semaste}
179254721Semaste
180314564Sdimsize_t BreakpointLocationList::GetNumResolvedLocations() const {
181314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
182314564Sdim  size_t resolve_count = 0;
183314564Sdim  collection::const_iterator pos, end = m_locations.end();
184314564Sdim  for (pos = m_locations.begin(); pos != end; ++pos) {
185314564Sdim    if ((*pos)->IsResolved())
186314564Sdim      ++resolve_count;
187314564Sdim  }
188314564Sdim  return resolve_count;
189254721Semaste}
190254721Semaste
191314564Sdimvoid BreakpointLocationList::GetDescription(Stream *s,
192314564Sdim                                            lldb::DescriptionLevel level) {
193314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
194314564Sdim  collection::iterator pos, end = m_locations.end();
195254721Semaste
196314564Sdim  for (pos = m_locations.begin(); pos != end; ++pos) {
197314564Sdim    s->Printf(" ");
198314564Sdim    (*pos)->GetDescription(s, level);
199314564Sdim  }
200254721Semaste}
201254721Semaste
202314564SdimBreakpointLocationSP BreakpointLocationList::AddLocation(
203314564Sdim    const Address &addr, bool resolve_indirect_symbols, bool *new_location) {
204314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
205254721Semaste
206314564Sdim  if (new_location)
207314564Sdim    *new_location = false;
208314564Sdim  BreakpointLocationSP bp_loc_sp(FindByAddress(addr));
209314564Sdim  if (!bp_loc_sp) {
210314564Sdim    bp_loc_sp = Create(addr, resolve_indirect_symbols);
211314564Sdim    if (bp_loc_sp) {
212314564Sdim      bp_loc_sp->ResolveBreakpointSite();
213254721Semaste
214314564Sdim      if (new_location)
215314564Sdim        *new_location = true;
216314564Sdim      if (m_new_location_recorder) {
217314564Sdim        m_new_location_recorder->Add(bp_loc_sp);
218314564Sdim      }
219314564Sdim    }
220314564Sdim  }
221314564Sdim  return bp_loc_sp;
222254721Semaste}
223254721Semaste
224314564Sdimvoid BreakpointLocationList::SwapLocation(
225314564Sdim    BreakpointLocationSP to_location_sp,
226314564Sdim    BreakpointLocationSP from_location_sp) {
227314564Sdim  if (!from_location_sp || !to_location_sp)
228314564Sdim    return;
229314564Sdim
230314564Sdim  m_address_to_location.erase(to_location_sp->GetAddress());
231314564Sdim  to_location_sp->SwapLocation(from_location_sp);
232314564Sdim  RemoveLocation(from_location_sp);
233314564Sdim  m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
234314564Sdim  to_location_sp->ResolveBreakpointSite();
235280031Sdim}
236280031Sdim
237314564Sdimbool BreakpointLocationList::RemoveLocation(
238314564Sdim    const lldb::BreakpointLocationSP &bp_loc_sp) {
239314564Sdim  if (bp_loc_sp) {
240314564Sdim    std::lock_guard<std::recursive_mutex> guard(m_mutex);
241309124Sdim
242314564Sdim    m_address_to_location.erase(bp_loc_sp->GetAddress());
243254721Semaste
244341825Sdim    size_t num_locations = m_locations.size();
245341825Sdim    for (size_t idx = 0; idx < num_locations; idx++) {
246341825Sdim      if (m_locations[idx].get() == bp_loc_sp.get()) {
247341825Sdim        RemoveLocationByIndex(idx);
248314564Sdim        return true;
249314564Sdim      }
250296417Sdim    }
251314564Sdim  }
252314564Sdim  return false;
253254721Semaste}
254254721Semaste
255341825Sdimvoid BreakpointLocationList::RemoveLocationByIndex(size_t idx) {
256341825Sdim  assert (idx < m_locations.size());
257341825Sdim  m_address_to_location.erase(m_locations[idx]->GetAddress());
258341825Sdim  m_locations.erase(m_locations.begin() + idx);
259341825Sdim}
260341825Sdim
261314564Sdimvoid BreakpointLocationList::RemoveInvalidLocations(const ArchSpec &arch) {
262314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
263314564Sdim  size_t idx = 0;
264341825Sdim  // Don't cache m_location.size() as it will change since we might remove
265341825Sdim  // locations from our vector...
266314564Sdim  while (idx < m_locations.size()) {
267314564Sdim    BreakpointLocation *bp_loc = m_locations[idx].get();
268314564Sdim    if (bp_loc->GetAddress().SectionWasDeleted()) {
269314564Sdim      // Section was deleted which means this breakpoint comes from a module
270314564Sdim      // that is no longer valid, so we should remove it.
271341825Sdim      RemoveLocationByIndex(idx);
272314564Sdim      continue;
273314564Sdim    }
274314564Sdim    if (arch.IsValid()) {
275314564Sdim      ModuleSP module_sp(bp_loc->GetAddress().GetModule());
276314564Sdim      if (module_sp) {
277314564Sdim        if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) {
278314564Sdim          // The breakpoint was in a module whose architecture is no longer
279314564Sdim          // compatible with "arch", so we need to remove it
280341825Sdim          RemoveLocationByIndex(idx);
281314564Sdim          continue;
282258884Semaste        }
283314564Sdim      }
284258884Semaste    }
285341825Sdim    // Only increment the index if we didn't remove the locations at index
286341825Sdim    // "idx"
287314564Sdim    ++idx;
288314564Sdim  }
289258884Semaste}
290254721Semaste
291314564Sdimvoid BreakpointLocationList::StartRecordingNewLocations(
292314564Sdim    BreakpointLocationCollection &new_locations) {
293314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
294314564Sdim  assert(m_new_location_recorder == nullptr);
295314564Sdim  m_new_location_recorder = &new_locations;
296254721Semaste}
297254721Semaste
298314564Sdimvoid BreakpointLocationList::StopRecordingNewLocations() {
299314564Sdim  std::lock_guard<std::recursive_mutex> guard(m_mutex);
300314564Sdim  m_new_location_recorder = nullptr;
301254721Semaste}
302254721Semaste
303314564Sdimvoid BreakpointLocationList::Compact() {
304314564Sdim  lldb::break_id_t highest_id = 0;
305314564Sdim
306314564Sdim  for (BreakpointLocationSP loc_sp : m_locations) {
307314564Sdim    lldb::break_id_t cur_id = loc_sp->GetID();
308314564Sdim    if (cur_id > highest_id)
309314564Sdim      highest_id = cur_id;
310314564Sdim  }
311314564Sdim  m_next_id = highest_id;
312280031Sdim}
313