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