xref: /src/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolver.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- BreakpointResolver.cpp --------------------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9f034231aSEd Maste #include "lldb/Breakpoint/BreakpointResolver.h"
10f034231aSEd Maste 
11f034231aSEd Maste #include "lldb/Breakpoint/Breakpoint.h"
12f034231aSEd Maste #include "lldb/Breakpoint/BreakpointLocation.h"
13f73363f1SDimitry Andric // Have to include the other breakpoint resolver types here so the static
14f73363f1SDimitry Andric // create from StructuredData can call them.
1514f1b3e8SDimitry Andric #include "lldb/Breakpoint/BreakpointResolverAddress.h"
1614f1b3e8SDimitry Andric #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
1714f1b3e8SDimitry Andric #include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
1814f1b3e8SDimitry Andric #include "lldb/Breakpoint/BreakpointResolverName.h"
1994994d37SDimitry Andric #include "lldb/Breakpoint/BreakpointResolverScripted.h"
2014f1b3e8SDimitry Andric #include "lldb/Core/Address.h"
21f034231aSEd Maste #include "lldb/Core/ModuleList.h"
22f034231aSEd Maste #include "lldb/Core/SearchFilter.h"
23f21a844fSEd Maste #include "lldb/Symbol/CompileUnit.h"
24f21a844fSEd Maste #include "lldb/Symbol/Function.h"
2514f1b3e8SDimitry Andric #include "lldb/Symbol/SymbolContext.h"
26ac9a064cSDimitry Andric #include "lldb/Target/Language.h"
2714f1b3e8SDimitry Andric #include "lldb/Target/Target.h"
28145449b1SDimitry Andric #include "lldb/Utility/LLDBLog.h"
2974a628f7SDimitry Andric #include "lldb/Utility/Log.h"
3074a628f7SDimitry Andric #include "lldb/Utility/Stream.h"
3174a628f7SDimitry Andric #include "lldb/Utility/StreamString.h"
32e3b55780SDimitry Andric #include <optional>
33f034231aSEd Maste 
34f034231aSEd Maste using namespace lldb_private;
35f21a844fSEd Maste using namespace lldb;
36f034231aSEd Maste 
37f034231aSEd Maste // BreakpointResolver:
3814f1b3e8SDimitry Andric const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",
3914f1b3e8SDimitry Andric                                                   "SymbolName",  "SourceRegex",
40ead24645SDimitry Andric                                                   "Python",   "Exception",
41ead24645SDimitry Andric                                                   "Unknown"};
4214f1b3e8SDimitry Andric 
4314f1b3e8SDimitry Andric const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
4414f1b3e8SDimitry Andric     BreakpointResolver::OptionNames::LastOptionName)] = {
4514f1b3e8SDimitry Andric     "AddressOffset", "Exact",     "FileName",     "Inlines",     "Language",
4694994d37SDimitry Andric     "LineNumber",    "Column",    "ModuleName",   "NameMask",    "Offset",
4794994d37SDimitry Andric     "PythonClass",   "Regex",     "ScriptArgs",   "SectionName", "SearchDepth",
4894994d37SDimitry Andric     "SkipPrologue",  "SymbolNames"};
4914f1b3e8SDimitry Andric 
ResolverTyToName(enum ResolverTy type)5014f1b3e8SDimitry Andric const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
5114f1b3e8SDimitry Andric   if (type > LastKnownResolverType)
5214f1b3e8SDimitry Andric     return g_ty_to_name[UnknownResolver];
5314f1b3e8SDimitry Andric 
5414f1b3e8SDimitry Andric   return g_ty_to_name[type];
55f034231aSEd Maste }
56f034231aSEd Maste 
5714f1b3e8SDimitry Andric BreakpointResolver::ResolverTy
NameToResolverTy(llvm::StringRef name)58b76161e4SDimitry Andric BreakpointResolver::NameToResolverTy(llvm::StringRef name) {
5914f1b3e8SDimitry Andric   for (size_t i = 0; i < LastKnownResolverType; i++) {
60b76161e4SDimitry Andric     if (name == g_ty_to_name[i])
6114f1b3e8SDimitry Andric       return (ResolverTy)i;
6214f1b3e8SDimitry Andric   }
6314f1b3e8SDimitry Andric   return UnknownResolver;
64f034231aSEd Maste }
65f034231aSEd Maste 
BreakpointResolver(const BreakpointSP & bkpt,const unsigned char resolverTy,lldb::addr_t offset)66cfca06d7SDimitry Andric BreakpointResolver::BreakpointResolver(const BreakpointSP &bkpt,
6714f1b3e8SDimitry Andric                                        const unsigned char resolverTy,
6814f1b3e8SDimitry Andric                                        lldb::addr_t offset)
6914f1b3e8SDimitry Andric     : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {}
7014f1b3e8SDimitry Andric 
71344a3780SDimitry Andric BreakpointResolver::~BreakpointResolver() = default;
7214f1b3e8SDimitry Andric 
CreateFromStructuredData(const StructuredData::Dictionary & resolver_dict,Status & error)7314f1b3e8SDimitry Andric BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
74b76161e4SDimitry Andric     const StructuredData::Dictionary &resolver_dict, Status &error) {
7514f1b3e8SDimitry Andric   BreakpointResolverSP result_sp;
7614f1b3e8SDimitry Andric   if (!resolver_dict.IsValid()) {
7714f1b3e8SDimitry Andric     error.SetErrorString("Can't deserialize from an invalid data object.");
7814f1b3e8SDimitry Andric     return result_sp;
7914f1b3e8SDimitry Andric   }
8014f1b3e8SDimitry Andric 
81b76161e4SDimitry Andric   llvm::StringRef subclass_name;
8214f1b3e8SDimitry Andric 
8314f1b3e8SDimitry Andric   bool success = resolver_dict.GetValueForKeyAsString(
8414f1b3e8SDimitry Andric       GetSerializationSubclassKey(), subclass_name);
8514f1b3e8SDimitry Andric 
8614f1b3e8SDimitry Andric   if (!success) {
87b60736ecSDimitry Andric     error.SetErrorString("Resolver data missing subclass resolver key");
8814f1b3e8SDimitry Andric     return result_sp;
8914f1b3e8SDimitry Andric   }
9014f1b3e8SDimitry Andric 
91b76161e4SDimitry Andric   ResolverTy resolver_type = NameToResolverTy(subclass_name);
9214f1b3e8SDimitry Andric   if (resolver_type == UnknownResolver) {
93b76161e4SDimitry Andric     error.SetErrorStringWithFormatv("Unknown resolver type: {0}.",
94b76161e4SDimitry Andric                                     subclass_name);
9514f1b3e8SDimitry Andric     return result_sp;
9614f1b3e8SDimitry Andric   }
9714f1b3e8SDimitry Andric 
9814f1b3e8SDimitry Andric   StructuredData::Dictionary *subclass_options = nullptr;
9914f1b3e8SDimitry Andric   success = resolver_dict.GetValueForKeyAsDictionary(
10014f1b3e8SDimitry Andric       GetSerializationSubclassOptionsKey(), subclass_options);
10114f1b3e8SDimitry Andric   if (!success || !subclass_options || !subclass_options->IsValid()) {
10214f1b3e8SDimitry Andric     error.SetErrorString("Resolver data missing subclass options key.");
10314f1b3e8SDimitry Andric     return result_sp;
10414f1b3e8SDimitry Andric   }
10514f1b3e8SDimitry Andric 
1067fa27ce4SDimitry Andric   lldb::offset_t offset;
10714f1b3e8SDimitry Andric   success = subclass_options->GetValueForKeyAsInteger(
10814f1b3e8SDimitry Andric       GetKey(OptionNames::Offset), offset);
10914f1b3e8SDimitry Andric   if (!success) {
11014f1b3e8SDimitry Andric     error.SetErrorString("Resolver data missing offset options key.");
11114f1b3e8SDimitry Andric     return result_sp;
11214f1b3e8SDimitry Andric   }
11314f1b3e8SDimitry Andric 
11414f1b3e8SDimitry Andric   switch (resolver_type) {
11514f1b3e8SDimitry Andric   case FileLineResolver:
116b1c73532SDimitry Andric     result_sp = BreakpointResolverFileLine::CreateFromStructuredData(
117312c0ed1SDimitry Andric         *subclass_options, error);
11814f1b3e8SDimitry Andric     break;
11914f1b3e8SDimitry Andric   case AddressResolver:
120b1c73532SDimitry Andric     result_sp = BreakpointResolverAddress::CreateFromStructuredData(
121312c0ed1SDimitry Andric         *subclass_options, error);
12214f1b3e8SDimitry Andric     break;
12314f1b3e8SDimitry Andric   case NameResolver:
124b1c73532SDimitry Andric     result_sp = BreakpointResolverName::CreateFromStructuredData(
125312c0ed1SDimitry Andric         *subclass_options, error);
12614f1b3e8SDimitry Andric     break;
12714f1b3e8SDimitry Andric   case FileRegexResolver:
128b1c73532SDimitry Andric     result_sp = BreakpointResolverFileRegex::CreateFromStructuredData(
129312c0ed1SDimitry Andric         *subclass_options, error);
13014f1b3e8SDimitry Andric     break;
13194994d37SDimitry Andric   case PythonResolver:
132b1c73532SDimitry Andric     result_sp = BreakpointResolverScripted::CreateFromStructuredData(
133312c0ed1SDimitry Andric         *subclass_options, error);
13494994d37SDimitry Andric     break;
13514f1b3e8SDimitry Andric   case ExceptionResolver:
13614f1b3e8SDimitry Andric     error.SetErrorString("Exception resolvers are hard.");
13714f1b3e8SDimitry Andric     break;
13814f1b3e8SDimitry Andric   default:
13914f1b3e8SDimitry Andric     llvm_unreachable("Should never get an unresolvable resolver type.");
14014f1b3e8SDimitry Andric   }
14114f1b3e8SDimitry Andric 
142b1c73532SDimitry Andric   if (error.Fail() || !result_sp)
143b1c73532SDimitry Andric     return {};
144145449b1SDimitry Andric 
14514f1b3e8SDimitry Andric   // Add on the global offset option:
146b1c73532SDimitry Andric   result_sp->SetOffset(offset);
147b1c73532SDimitry Andric   return result_sp;
14814f1b3e8SDimitry Andric }
14914f1b3e8SDimitry Andric 
WrapOptionsDict(StructuredData::DictionarySP options_dict_sp)15014f1b3e8SDimitry Andric StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict(
15114f1b3e8SDimitry Andric     StructuredData::DictionarySP options_dict_sp) {
15214f1b3e8SDimitry Andric   if (!options_dict_sp || !options_dict_sp->IsValid())
15314f1b3e8SDimitry Andric     return StructuredData::DictionarySP();
15414f1b3e8SDimitry Andric 
15514f1b3e8SDimitry Andric   StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary());
15614f1b3e8SDimitry Andric   type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetResolverName());
15714f1b3e8SDimitry Andric   type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
15814f1b3e8SDimitry Andric 
15914f1b3e8SDimitry Andric   // Add the m_offset to the dictionary:
16014f1b3e8SDimitry Andric   options_dict_sp->AddIntegerItem(GetKey(OptionNames::Offset), m_offset);
16114f1b3e8SDimitry Andric 
16214f1b3e8SDimitry Andric   return type_dict_sp;
16314f1b3e8SDimitry Andric }
16414f1b3e8SDimitry Andric 
SetBreakpoint(const BreakpointSP & bkpt)165cfca06d7SDimitry Andric void BreakpointResolver::SetBreakpoint(const BreakpointSP &bkpt) {
166cfca06d7SDimitry Andric   assert(bkpt);
167f034231aSEd Maste   m_breakpoint = bkpt;
16894994d37SDimitry Andric   NotifyBreakpointSet();
169f034231aSEd Maste }
170f034231aSEd Maste 
ResolveBreakpointInModules(SearchFilter & filter,ModuleList & modules)17114f1b3e8SDimitry Andric void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter,
17214f1b3e8SDimitry Andric                                                     ModuleList &modules) {
173f034231aSEd Maste   filter.SearchInModuleList(*this, modules);
174f034231aSEd Maste }
175f034231aSEd Maste 
ResolveBreakpoint(SearchFilter & filter)17614f1b3e8SDimitry Andric void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) {
177f034231aSEd Maste   filter.Search(*this);
178f034231aSEd Maste }
179f034231aSEd Maste 
18094994d37SDimitry Andric namespace {
18194994d37SDimitry Andric struct SourceLoc {
18294994d37SDimitry Andric   uint32_t line = UINT32_MAX;
183344a3780SDimitry Andric   uint16_t column;
SourceLoc__anon18021be10111::SourceLoc184e3b55780SDimitry Andric   SourceLoc(uint32_t l, std::optional<uint16_t> c)
185344a3780SDimitry Andric       : line(l), column(c ? *c : LLDB_INVALID_COLUMN_NUMBER) {}
SourceLoc__anon18021be10111::SourceLoc18694994d37SDimitry Andric   SourceLoc(const SymbolContext &sc)
18794994d37SDimitry Andric       : line(sc.line_entry.line),
188344a3780SDimitry Andric         column(sc.line_entry.column ? sc.line_entry.column
189344a3780SDimitry Andric                                     : LLDB_INVALID_COLUMN_NUMBER) {}
19094994d37SDimitry Andric };
19194994d37SDimitry Andric 
operator <(const SourceLoc lhs,const SourceLoc rhs)192344a3780SDimitry Andric bool operator<(const SourceLoc lhs, const SourceLoc rhs) {
193344a3780SDimitry Andric   if (lhs.line < rhs.line)
19494994d37SDimitry Andric     return true;
195344a3780SDimitry Andric   if (lhs.line > rhs.line)
19694994d37SDimitry Andric     return false;
197344a3780SDimitry Andric   //  uint32_t a_col = lhs.column ? lhs.column : LLDB_INVALID_COLUMN_NUMBER;
198344a3780SDimitry Andric   //  uint32_t b_col = rhs.column ? rhs.column : LLDB_INVALID_COLUMN_NUMBER;
199344a3780SDimitry Andric   return lhs.column < rhs.column;
20094994d37SDimitry Andric }
20194994d37SDimitry Andric } // namespace
20294994d37SDimitry Andric 
SetSCMatchesByLine(SearchFilter & filter,SymbolContextList & sc_list,bool skip_prologue,llvm::StringRef log_ident,uint32_t line,std::optional<uint16_t> column)203344a3780SDimitry Andric void BreakpointResolver::SetSCMatchesByLine(
204344a3780SDimitry Andric     SearchFilter &filter, SymbolContextList &sc_list, bool skip_prologue,
205e3b55780SDimitry Andric     llvm::StringRef log_ident, uint32_t line, std::optional<uint16_t> column) {
20694994d37SDimitry Andric   llvm::SmallVector<SymbolContext, 16> all_scs;
207ac9a064cSDimitry Andric 
208ac9a064cSDimitry Andric   for (const auto &sc : sc_list) {
209ac9a064cSDimitry Andric     if (Language::GetGlobalLanguageProperties()
210ac9a064cSDimitry Andric             .GetEnableFilterForLineBreakpoints())
211ac9a064cSDimitry Andric       if (Language *lang = Language::FindPlugin(sc.GetLanguage());
212ac9a064cSDimitry Andric           lang && lang->IgnoreForLineBreakpoints(sc))
213ac9a064cSDimitry Andric         continue;
214ac9a064cSDimitry Andric     all_scs.push_back(sc);
215ac9a064cSDimitry Andric   }
21694994d37SDimitry Andric 
21794994d37SDimitry Andric   while (all_scs.size()) {
21894994d37SDimitry Andric     uint32_t closest_line = UINT32_MAX;
21994994d37SDimitry Andric 
22094994d37SDimitry Andric     // Move all the elements with a matching file spec to the end.
22194994d37SDimitry Andric     auto &match = all_scs[0];
22294994d37SDimitry Andric     auto worklist_begin = std::partition(
22394994d37SDimitry Andric         all_scs.begin(), all_scs.end(), [&](const SymbolContext &sc) {
224ac9a064cSDimitry Andric           if (sc.line_entry.GetFile() == match.line_entry.GetFile() ||
225ac9a064cSDimitry Andric               sc.line_entry.original_file_sp->Equal(
226ac9a064cSDimitry Andric                   *match.line_entry.original_file_sp,
227ac9a064cSDimitry Andric                   SupportFile::eEqualFileSpecAndChecksumIfSet)) {
22894994d37SDimitry Andric             // When a match is found, keep track of the smallest line number.
22994994d37SDimitry Andric             closest_line = std::min(closest_line, sc.line_entry.line);
23094994d37SDimitry Andric             return false;
23194994d37SDimitry Andric           }
23294994d37SDimitry Andric           return true;
23394994d37SDimitry Andric         });
23494994d37SDimitry Andric 
23594994d37SDimitry Andric     // (worklist_begin, worklist_end) now contains all entries for one filespec.
23694994d37SDimitry Andric     auto worklist_end = all_scs.end();
23794994d37SDimitry Andric 
23894994d37SDimitry Andric     if (column) {
23994994d37SDimitry Andric       // If a column was requested, do a more precise match and only
240344a3780SDimitry Andric       // return the first location that comes before or at the
24194994d37SDimitry Andric       // requested location.
242344a3780SDimitry Andric       SourceLoc requested(line, *column);
24394994d37SDimitry Andric       // First, filter out all entries left of the requested column.
24494994d37SDimitry Andric       worklist_end = std::remove_if(
24594994d37SDimitry Andric           worklist_begin, worklist_end,
246344a3780SDimitry Andric           [&](const SymbolContext &sc) { return requested < SourceLoc(sc); });
24794994d37SDimitry Andric       // Sort the remaining entries by (line, column).
24894994d37SDimitry Andric       llvm::sort(worklist_begin, worklist_end,
24994994d37SDimitry Andric                  [](const SymbolContext &a, const SymbolContext &b) {
25094994d37SDimitry Andric                    return SourceLoc(a) < SourceLoc(b);
25194994d37SDimitry Andric                  });
25294994d37SDimitry Andric 
25394994d37SDimitry Andric       // Filter out all locations with a source location after the closest match.
25494994d37SDimitry Andric       if (worklist_begin != worklist_end)
25594994d37SDimitry Andric         worklist_end = std::remove_if(
25694994d37SDimitry Andric             worklist_begin, worklist_end, [&](const SymbolContext &sc) {
25794994d37SDimitry Andric               return SourceLoc(*worklist_begin) < SourceLoc(sc);
25894994d37SDimitry Andric             });
25994994d37SDimitry Andric     } else {
26094994d37SDimitry Andric       // Remove all entries with a larger line number.
26194994d37SDimitry Andric       // ResolveSymbolContext will always return a number that is >=
26294994d37SDimitry Andric       // the line number you pass in. So the smaller line number is
26394994d37SDimitry Andric       // always better.
26494994d37SDimitry Andric       worklist_end = std::remove_if(worklist_begin, worklist_end,
26594994d37SDimitry Andric                                     [&](const SymbolContext &sc) {
26694994d37SDimitry Andric                                       return closest_line != sc.line_entry.line;
26794994d37SDimitry Andric                                     });
26894994d37SDimitry Andric     }
26994994d37SDimitry Andric 
27094994d37SDimitry Andric     // Sort by file address.
27194994d37SDimitry Andric     llvm::sort(worklist_begin, worklist_end,
27294994d37SDimitry Andric                [](const SymbolContext &a, const SymbolContext &b) {
27394994d37SDimitry Andric                  return a.line_entry.range.GetBaseAddress().GetFileAddress() <
27494994d37SDimitry Andric                         b.line_entry.range.GetBaseAddress().GetFileAddress();
27594994d37SDimitry Andric                });
27694994d37SDimitry Andric 
27794994d37SDimitry Andric     // Go through and see if there are line table entries that are
27894994d37SDimitry Andric     // contiguous, and if so keep only the first of the contiguous range.
27994994d37SDimitry Andric     // We do this by picking the first location in each lexical block.
28094994d37SDimitry Andric     llvm::SmallDenseSet<Block *, 8> blocks_with_breakpoints;
28194994d37SDimitry Andric     for (auto first = worklist_begin; first != worklist_end; ++first) {
28294994d37SDimitry Andric       assert(!blocks_with_breakpoints.count(first->block));
28394994d37SDimitry Andric       blocks_with_breakpoints.insert(first->block);
28494994d37SDimitry Andric       worklist_end =
28594994d37SDimitry Andric           std::remove_if(std::next(first), worklist_end,
28694994d37SDimitry Andric                          [&](const SymbolContext &sc) {
28794994d37SDimitry Andric                            return blocks_with_breakpoints.count(sc.block);
28894994d37SDimitry Andric                          });
28994994d37SDimitry Andric     }
29094994d37SDimitry Andric 
29194994d37SDimitry Andric     // Make breakpoints out of the closest line number match.
29294994d37SDimitry Andric     for (auto &sc : llvm::make_range(worklist_begin, worklist_end))
29394994d37SDimitry Andric       AddLocation(filter, sc, skip_prologue, log_ident);
29494994d37SDimitry Andric 
29594994d37SDimitry Andric     // Remove all contexts processed by this iteration.
29694994d37SDimitry Andric     all_scs.erase(worklist_begin, all_scs.end());
29794994d37SDimitry Andric   }
29894994d37SDimitry Andric }
29994994d37SDimitry Andric 
AddLocation(SearchFilter & filter,const SymbolContext & sc,bool skip_prologue,llvm::StringRef log_ident)30094994d37SDimitry Andric void BreakpointResolver::AddLocation(SearchFilter &filter,
30194994d37SDimitry Andric                                      const SymbolContext &sc,
30294994d37SDimitry Andric                                      bool skip_prologue,
30314f1b3e8SDimitry Andric                                      llvm::StringRef log_ident) {
304145449b1SDimitry Andric   Log *log = GetLog(LLDBLog::Breakpoints);
305f21a844fSEd Maste   Address line_start = sc.line_entry.range.GetBaseAddress();
30694994d37SDimitry Andric   if (!line_start.IsValid()) {
307ead24645SDimitry Andric     LLDB_LOGF(log,
308ead24645SDimitry Andric               "error: Unable to set breakpoint %s at file address "
30994994d37SDimitry Andric               "0x%" PRIx64 "\n",
31094994d37SDimitry Andric               log_ident.str().c_str(), line_start.GetFileAddress());
31194994d37SDimitry Andric     return;
31294994d37SDimitry Andric   }
31394994d37SDimitry Andric 
31494994d37SDimitry Andric   if (!filter.AddressPasses(line_start)) {
315ead24645SDimitry Andric     LLDB_LOGF(log,
316ead24645SDimitry Andric               "Breakpoint %s at file address 0x%" PRIx64
31794994d37SDimitry Andric               " didn't pass the filter.\n",
31894994d37SDimitry Andric               log_ident.str().c_str(), line_start.GetFileAddress());
31994994d37SDimitry Andric   }
32094994d37SDimitry Andric 
321f21a844fSEd Maste   // If the line number is before the prologue end, move it there...
322f21a844fSEd Maste   bool skipped_prologue = false;
32394994d37SDimitry Andric   if (skip_prologue && sc.function) {
32494994d37SDimitry Andric     Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress());
32514f1b3e8SDimitry Andric     if (prologue_addr.IsValid() && (line_start == prologue_addr)) {
32694994d37SDimitry Andric       const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
32714f1b3e8SDimitry Andric       if (prologue_byte_size) {
328f21a844fSEd Maste         prologue_addr.Slide(prologue_byte_size);
329f21a844fSEd Maste 
33014f1b3e8SDimitry Andric         if (filter.AddressPasses(prologue_addr)) {
331f21a844fSEd Maste           skipped_prologue = true;
332f21a844fSEd Maste           line_start = prologue_addr;
333f21a844fSEd Maste         }
334f21a844fSEd Maste       }
335f21a844fSEd Maste     }
336f21a844fSEd Maste   }
337f21a844fSEd Maste 
338f3fbd1c0SDimitry Andric   BreakpointLocationSP bp_loc_sp(AddLocation(line_start));
339cfca06d7SDimitry Andric   if (log && bp_loc_sp && !GetBreakpoint()->IsInternal()) {
340f21a844fSEd Maste     StreamString s;
341f21a844fSEd Maste     bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
342ead24645SDimitry Andric     LLDB_LOGF(log, "Added location (skipped prologue: %s): %s \n",
34314f1b3e8SDimitry Andric               skipped_prologue ? "yes" : "no", s.GetData());
344f21a844fSEd Maste   }
345f21a844fSEd Maste }
346f3fbd1c0SDimitry Andric 
AddLocation(Address loc_addr,bool * new_location)34714f1b3e8SDimitry Andric BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr,
34814f1b3e8SDimitry Andric                                                      bool *new_location) {
349f3fbd1c0SDimitry Andric   loc_addr.Slide(m_offset);
350cfca06d7SDimitry Andric   return GetBreakpoint()->AddLocation(loc_addr, new_location);
351f3fbd1c0SDimitry Andric }
352f3fbd1c0SDimitry Andric 
SetOffset(lldb::addr_t offset)35314f1b3e8SDimitry Andric void BreakpointResolver::SetOffset(lldb::addr_t offset) {
35414f1b3e8SDimitry Andric   // There may already be an offset, so we are actually adjusting location
35514f1b3e8SDimitry Andric   // addresses by the difference.
356f3fbd1c0SDimitry Andric   // lldb::addr_t slide = offset - m_offset;
35794994d37SDimitry Andric   // FIXME: We should go fix up all the already set locations for the new
35894994d37SDimitry Andric   // slide.
359f3fbd1c0SDimitry Andric 
360f3fbd1c0SDimitry Andric   m_offset = offset;
361f3fbd1c0SDimitry Andric }
362