15ffd83dbSDimitry Andric //===-- BreakpointResolverFileLine.cpp ------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
100b57cec5SDimitry Andric
110b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
120b57cec5SDimitry Andric #include "lldb/Core/Module.h"
130b57cec5SDimitry Andric #include "lldb/Symbol/CompileUnit.h"
140b57cec5SDimitry Andric #include "lldb/Symbol/Function.h"
15bdd1243dSDimitry Andric #include "lldb/Target/Target.h"
1681ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
170b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
180b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
19bdd1243dSDimitry Andric #include <optional>
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric using namespace lldb;
220b57cec5SDimitry Andric using namespace lldb_private;
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric // BreakpointResolverFileLine:
BreakpointResolverFileLine(const BreakpointSP & bkpt,lldb::addr_t offset,bool skip_prologue,const SourceLocationSpec & location_spec,std::optional<llvm::StringRef> removed_prefix_opt)250b57cec5SDimitry Andric BreakpointResolverFileLine::BreakpointResolverFileLine(
26fe6060f1SDimitry Andric const BreakpointSP &bkpt, lldb::addr_t offset, bool skip_prologue,
27bdd1243dSDimitry Andric const SourceLocationSpec &location_spec,
28bdd1243dSDimitry Andric std::optional<llvm::StringRef> removed_prefix_opt)
290b57cec5SDimitry Andric : BreakpointResolver(bkpt, BreakpointResolver::FileLineResolver, offset),
30bdd1243dSDimitry Andric m_location_spec(location_spec), m_skip_prologue(skip_prologue),
31bdd1243dSDimitry Andric m_removed_prefix_opt(removed_prefix_opt) {}
320b57cec5SDimitry Andric
CreateFromStructuredData(const StructuredData::Dictionary & options_dict,Status & error)33*c9157d92SDimitry Andric BreakpointResolverSP BreakpointResolverFileLine::CreateFromStructuredData(
34*c9157d92SDimitry Andric const StructuredData::Dictionary &options_dict, Status &error) {
350b57cec5SDimitry Andric llvm::StringRef filename;
36fe6060f1SDimitry Andric uint32_t line;
37fe6060f1SDimitry Andric uint16_t column;
380b57cec5SDimitry Andric bool check_inlines;
390b57cec5SDimitry Andric bool skip_prologue;
400b57cec5SDimitry Andric bool exact_match;
410b57cec5SDimitry Andric bool success;
420b57cec5SDimitry Andric
430b57cec5SDimitry Andric lldb::addr_t offset = 0;
440b57cec5SDimitry Andric
450b57cec5SDimitry Andric success = options_dict.GetValueForKeyAsString(GetKey(OptionNames::FileName),
460b57cec5SDimitry Andric filename);
470b57cec5SDimitry Andric if (!success) {
480b57cec5SDimitry Andric error.SetErrorString("BRFL::CFSD: Couldn't find filename entry.");
490b57cec5SDimitry Andric return nullptr;
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric
520b57cec5SDimitry Andric success = options_dict.GetValueForKeyAsInteger(
53fe6060f1SDimitry Andric GetKey(OptionNames::LineNumber), line);
540b57cec5SDimitry Andric if (!success) {
550b57cec5SDimitry Andric error.SetErrorString("BRFL::CFSD: Couldn't find line number entry.");
560b57cec5SDimitry Andric return nullptr;
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric
590b57cec5SDimitry Andric success =
600b57cec5SDimitry Andric options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Column), column);
610b57cec5SDimitry Andric if (!success) {
620b57cec5SDimitry Andric // Backwards compatibility.
630b57cec5SDimitry Andric column = 0;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric success = options_dict.GetValueForKeyAsBoolean(GetKey(OptionNames::Inlines),
670b57cec5SDimitry Andric check_inlines);
680b57cec5SDimitry Andric if (!success) {
690b57cec5SDimitry Andric error.SetErrorString("BRFL::CFSD: Couldn't find check inlines entry.");
700b57cec5SDimitry Andric return nullptr;
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric
730b57cec5SDimitry Andric success = options_dict.GetValueForKeyAsBoolean(
740b57cec5SDimitry Andric GetKey(OptionNames::SkipPrologue), skip_prologue);
750b57cec5SDimitry Andric if (!success) {
760b57cec5SDimitry Andric error.SetErrorString("BRFL::CFSD: Couldn't find skip prologue entry.");
770b57cec5SDimitry Andric return nullptr;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric
800b57cec5SDimitry Andric success = options_dict.GetValueForKeyAsBoolean(
810b57cec5SDimitry Andric GetKey(OptionNames::ExactMatch), exact_match);
820b57cec5SDimitry Andric if (!success) {
830b57cec5SDimitry Andric error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
840b57cec5SDimitry Andric return nullptr;
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric
87fe6060f1SDimitry Andric SourceLocationSpec location_spec(FileSpec(filename), line, column,
88fe6060f1SDimitry Andric check_inlines, exact_match);
89fe6060f1SDimitry Andric if (!location_spec)
90fe6060f1SDimitry Andric return nullptr;
910b57cec5SDimitry Andric
92*c9157d92SDimitry Andric return std::make_shared<BreakpointResolverFileLine>(
93*c9157d92SDimitry Andric nullptr, offset, skip_prologue, location_spec);
940b57cec5SDimitry Andric }
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric StructuredData::ObjectSP
SerializeToStructuredData()970b57cec5SDimitry Andric BreakpointResolverFileLine::SerializeToStructuredData() {
980b57cec5SDimitry Andric StructuredData::DictionarySP options_dict_sp(
990b57cec5SDimitry Andric new StructuredData::Dictionary());
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
1020b57cec5SDimitry Andric m_skip_prologue);
103fe6060f1SDimitry Andric options_dict_sp->AddStringItem(GetKey(OptionNames::FileName),
104fe6060f1SDimitry Andric m_location_spec.GetFileSpec().GetPath());
105fe6060f1SDimitry Andric options_dict_sp->AddIntegerItem(GetKey(OptionNames::LineNumber),
10681ad6265SDimitry Andric m_location_spec.GetLine().value_or(0));
107fe6060f1SDimitry Andric options_dict_sp->AddIntegerItem(
108fe6060f1SDimitry Andric GetKey(OptionNames::Column),
10981ad6265SDimitry Andric m_location_spec.GetColumn().value_or(LLDB_INVALID_COLUMN_NUMBER));
110fe6060f1SDimitry Andric options_dict_sp->AddBooleanItem(GetKey(OptionNames::Inlines),
111fe6060f1SDimitry Andric m_location_spec.GetCheckInlines());
1120b57cec5SDimitry Andric options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
113fe6060f1SDimitry Andric m_location_spec.GetExactMatch());
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric return WrapOptionsDict(options_dict_sp);
1160b57cec5SDimitry Andric }
1170b57cec5SDimitry Andric
1180b57cec5SDimitry Andric // Filter the symbol context list to remove contexts where the line number was
1190b57cec5SDimitry Andric // moved into a new function. We do this conservatively, so if e.g. we cannot
1200b57cec5SDimitry Andric // resolve the function in the context (which can happen in case of line-table-
1210b57cec5SDimitry Andric // only debug info), we leave the context as is. The trickiest part here is
1220b57cec5SDimitry Andric // handling inlined functions -- in this case we need to make sure we look at
1230b57cec5SDimitry Andric // the declaration line of the inlined function, NOT the function it was
1240b57cec5SDimitry Andric // inlined into.
FilterContexts(SymbolContextList & sc_list)125bdd1243dSDimitry Andric void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list) {
126fe6060f1SDimitry Andric if (m_location_spec.GetExactMatch())
1270b57cec5SDimitry Andric return; // Nothing to do. Contexts are precise.
1280b57cec5SDimitry Andric
12981ad6265SDimitry Andric Log *log = GetLog(LLDBLog::Breakpoints);
1300b57cec5SDimitry Andric for(uint32_t i = 0; i < sc_list.GetSize(); ++i) {
1310b57cec5SDimitry Andric SymbolContext sc;
1320b57cec5SDimitry Andric sc_list.GetContextAtIndex(i, sc);
1330b57cec5SDimitry Andric if (!sc.block)
1340b57cec5SDimitry Andric continue;
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andric FileSpec file;
1370b57cec5SDimitry Andric uint32_t line;
1380b57cec5SDimitry Andric const Block *inline_block = sc.block->GetContainingInlinedBlock();
1390b57cec5SDimitry Andric if (inline_block) {
1400b57cec5SDimitry Andric const Declaration &inline_declaration = inline_block->GetInlinedFunctionInfo()->GetDeclaration();
1410b57cec5SDimitry Andric if (!inline_declaration.IsValid())
1420b57cec5SDimitry Andric continue;
1430b57cec5SDimitry Andric file = inline_declaration.GetFile();
1440b57cec5SDimitry Andric line = inline_declaration.GetLine();
1450b57cec5SDimitry Andric } else if (sc.function)
1460b57cec5SDimitry Andric sc.function->GetStartLineSourceInfo(file, line);
1470b57cec5SDimitry Andric else
1480b57cec5SDimitry Andric continue;
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric if (file != sc.line_entry.file) {
1510b57cec5SDimitry Andric LLDB_LOG(log, "unexpected symbol context file {0}", sc.line_entry.file);
1520b57cec5SDimitry Andric continue;
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
1550b57cec5SDimitry Andric // Compare the requested line number with the line of the function
1560b57cec5SDimitry Andric // declaration. In case of a function declared as:
1570b57cec5SDimitry Andric //
1580b57cec5SDimitry Andric // int
1590b57cec5SDimitry Andric // foo()
1600b57cec5SDimitry Andric // {
1610b57cec5SDimitry Andric // ...
1620b57cec5SDimitry Andric //
1630b57cec5SDimitry Andric // the compiler will set the declaration line to the "foo" line, which is
1640b57cec5SDimitry Andric // the reason why we have -1 here. This can fail in case of two inline
1650b57cec5SDimitry Andric // functions defined back-to-back:
1660b57cec5SDimitry Andric //
1670b57cec5SDimitry Andric // inline int foo1() { ... }
1680b57cec5SDimitry Andric // inline int foo2() { ... }
1690b57cec5SDimitry Andric //
1700b57cec5SDimitry Andric // but that's the best we can do for now.
1710b57cec5SDimitry Andric // One complication, if the line number returned from GetStartLineSourceInfo
1720b57cec5SDimitry Andric // is 0, then we can't do this calculation. That can happen if
1730b57cec5SDimitry Andric // GetStartLineSourceInfo gets an error, or if the first line number in
1740b57cec5SDimitry Andric // the function really is 0 - which happens for some languages.
175e8d8bef9SDimitry Andric
176e8d8bef9SDimitry Andric // But only do this calculation if the line number we found in the SC
177e8d8bef9SDimitry Andric // was different from the one requested in the source file. If we actually
178e8d8bef9SDimitry Andric // found an exact match it must be valid.
179e8d8bef9SDimitry Andric
180fe6060f1SDimitry Andric if (m_location_spec.GetLine() == sc.line_entry.line)
181e8d8bef9SDimitry Andric continue;
182e8d8bef9SDimitry Andric
1830b57cec5SDimitry Andric const int decl_line_is_too_late_fudge = 1;
184fe6060f1SDimitry Andric if (line &&
185fe6060f1SDimitry Andric m_location_spec.GetLine() < line - decl_line_is_too_late_fudge) {
1860b57cec5SDimitry Andric LLDB_LOG(log, "removing symbol context at {0}:{1}", file, line);
1870b57cec5SDimitry Andric sc_list.RemoveContextAtIndex(i);
1880b57cec5SDimitry Andric --i;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric
DeduceSourceMapping(const SymbolContextList & sc_list)193bdd1243dSDimitry Andric void BreakpointResolverFileLine::DeduceSourceMapping(
194fe013be4SDimitry Andric const SymbolContextList &sc_list) {
195bdd1243dSDimitry Andric Target &target = GetBreakpoint()->GetTarget();
196bdd1243dSDimitry Andric if (!target.GetAutoSourceMapRelative())
197bdd1243dSDimitry Andric return;
198bdd1243dSDimitry Andric
199bdd1243dSDimitry Andric Log *log = GetLog(LLDBLog::Breakpoints);
200bdd1243dSDimitry Andric const llvm::StringRef path_separator = llvm::sys::path::get_separator(
201bdd1243dSDimitry Andric m_location_spec.GetFileSpec().GetPathStyle());
202bdd1243dSDimitry Andric // Check if "b" is a suffix of "a".
203bdd1243dSDimitry Andric // And return std::nullopt if not or the new path
204bdd1243dSDimitry Andric // of "a" after consuming "b" from the back.
205bdd1243dSDimitry Andric auto check_suffix =
206bdd1243dSDimitry Andric [path_separator](llvm::StringRef a, llvm::StringRef b,
207bdd1243dSDimitry Andric bool case_sensitive) -> std::optional<llvm::StringRef> {
208bdd1243dSDimitry Andric if (case_sensitive ? a.consume_back(b) : a.consume_back_insensitive(b)) {
209*c9157d92SDimitry Andric if (a.empty() || a.ends_with(path_separator)) {
210bdd1243dSDimitry Andric return a;
211bdd1243dSDimitry Andric }
212bdd1243dSDimitry Andric }
213bdd1243dSDimitry Andric return std::nullopt;
214bdd1243dSDimitry Andric };
215bdd1243dSDimitry Andric
216bdd1243dSDimitry Andric FileSpec request_file = m_location_spec.GetFileSpec();
217bdd1243dSDimitry Andric
218bdd1243dSDimitry Andric // Only auto deduce source map if breakpoint is full path.
219bdd1243dSDimitry Andric // Note: an existing source map reverse mapping (m_removed_prefix_opt has
220bdd1243dSDimitry Andric // value) may make request_file relative.
221bdd1243dSDimitry Andric if (!m_removed_prefix_opt.has_value() && request_file.IsRelative())
222bdd1243dSDimitry Andric return;
223bdd1243dSDimitry Andric
224bdd1243dSDimitry Andric const bool case_sensitive = request_file.IsCaseSensitive();
225fe013be4SDimitry Andric for (const SymbolContext &sc : sc_list) {
226bdd1243dSDimitry Andric FileSpec sc_file = sc.line_entry.file;
227bdd1243dSDimitry Andric
228bdd1243dSDimitry Andric if (FileSpec::Equal(sc_file, request_file, /*full*/ true))
229bdd1243dSDimitry Andric continue;
230bdd1243dSDimitry Andric
231bdd1243dSDimitry Andric llvm::StringRef sc_file_dir = sc_file.GetDirectory().GetStringRef();
232bdd1243dSDimitry Andric llvm::StringRef request_file_dir =
233bdd1243dSDimitry Andric request_file.GetDirectory().GetStringRef();
234bdd1243dSDimitry Andric
235bdd1243dSDimitry Andric llvm::StringRef new_mapping_from;
236bdd1243dSDimitry Andric llvm::SmallString<256> new_mapping_to;
237bdd1243dSDimitry Andric
238bdd1243dSDimitry Andric // Adding back any potentially reverse mapping stripped prefix.
239bdd1243dSDimitry Andric // for new_mapping_to.
240bdd1243dSDimitry Andric if (m_removed_prefix_opt.has_value())
241bdd1243dSDimitry Andric llvm::sys::path::append(new_mapping_to, *m_removed_prefix_opt);
242bdd1243dSDimitry Andric
243bdd1243dSDimitry Andric std::optional<llvm::StringRef> new_mapping_from_opt =
244bdd1243dSDimitry Andric check_suffix(sc_file_dir, request_file_dir, case_sensitive);
245bdd1243dSDimitry Andric if (new_mapping_from_opt) {
246bdd1243dSDimitry Andric new_mapping_from = *new_mapping_from_opt;
247bdd1243dSDimitry Andric if (new_mapping_to.empty())
248bdd1243dSDimitry Andric new_mapping_to = ".";
249bdd1243dSDimitry Andric } else {
250bdd1243dSDimitry Andric std::optional<llvm::StringRef> new_mapping_to_opt =
251bdd1243dSDimitry Andric check_suffix(request_file_dir, sc_file_dir, case_sensitive);
252bdd1243dSDimitry Andric if (new_mapping_to_opt) {
253bdd1243dSDimitry Andric new_mapping_from = ".";
254bdd1243dSDimitry Andric llvm::sys::path::append(new_mapping_to, *new_mapping_to_opt);
255bdd1243dSDimitry Andric }
256bdd1243dSDimitry Andric }
257bdd1243dSDimitry Andric
258bdd1243dSDimitry Andric if (!new_mapping_from.empty() && !new_mapping_to.empty()) {
259bdd1243dSDimitry Andric LLDB_LOG(log, "generating auto source map from {0} to {1}",
260bdd1243dSDimitry Andric new_mapping_from, new_mapping_to);
261bdd1243dSDimitry Andric if (target.GetSourcePathMap().AppendUnique(new_mapping_from,
262bdd1243dSDimitry Andric new_mapping_to,
263bdd1243dSDimitry Andric /*notify*/ true))
264bdd1243dSDimitry Andric target.GetStatistics().IncreaseSourceMapDeduceCount();
265bdd1243dSDimitry Andric }
266bdd1243dSDimitry Andric }
267bdd1243dSDimitry Andric }
268bdd1243dSDimitry Andric
SearchCallback(SearchFilter & filter,SymbolContext & context,Address * addr)2699dba64beSDimitry Andric Searcher::CallbackReturn BreakpointResolverFileLine::SearchCallback(
2709dba64beSDimitry Andric SearchFilter &filter, SymbolContext &context, Address *addr) {
2710b57cec5SDimitry Andric SymbolContextList sc_list;
2720b57cec5SDimitry Andric
2730b57cec5SDimitry Andric // There is a tricky bit here. You can have two compilation units that
2740b57cec5SDimitry Andric // #include the same file, and in one of them the function at m_line_number
2750b57cec5SDimitry Andric // is used (and so code and a line entry for it is generated) but in the
2760b57cec5SDimitry Andric // other it isn't. If we considered the CU's independently, then in the
2770b57cec5SDimitry Andric // second inclusion, we'd move the breakpoint to the next function that
2780b57cec5SDimitry Andric // actually generated code in the header file. That would end up being
2790b57cec5SDimitry Andric // confusing. So instead, we do the CU iterations by hand here, then scan
2800b57cec5SDimitry Andric // through the complete list of matches, and figure out the closest line
2810b57cec5SDimitry Andric // number match, and only set breakpoints on that match.
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric // Note also that if file_spec only had a file name and not a directory,
2840b57cec5SDimitry Andric // there may be many different file spec's in the resultant list. The
2850b57cec5SDimitry Andric // closest line match for one will not be right for some totally different
2860b57cec5SDimitry Andric // file. So we go through the match list and pull out the sets that have the
2870b57cec5SDimitry Andric // same file spec in their line_entry and treat each set separately.
2880b57cec5SDimitry Andric
28981ad6265SDimitry Andric const uint32_t line = m_location_spec.GetLine().value_or(0);
290bdd1243dSDimitry Andric const std::optional<uint16_t> column = m_location_spec.GetColumn();
2910b57cec5SDimitry Andric
2920b57cec5SDimitry Andric const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
2930b57cec5SDimitry Andric for (size_t i = 0; i < num_comp_units; i++) {
2940b57cec5SDimitry Andric CompUnitSP cu_sp(context.module_sp->GetCompileUnitAtIndex(i));
2950b57cec5SDimitry Andric if (cu_sp) {
2960b57cec5SDimitry Andric if (filter.CompUnitPasses(*cu_sp))
297bdd1243dSDimitry Andric cu_sp->ResolveSymbolContext(m_location_spec, eSymbolContextEverything,
298bdd1243dSDimitry Andric sc_list);
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric }
3010b57cec5SDimitry Andric
302bdd1243dSDimitry Andric FilterContexts(sc_list);
303bdd1243dSDimitry Andric
304bdd1243dSDimitry Andric DeduceSourceMapping(sc_list);
3050b57cec5SDimitry Andric
3060b57cec5SDimitry Andric StreamString s;
307fe6060f1SDimitry Andric s.Printf("for %s:%d ",
308fe6060f1SDimitry Andric m_location_spec.GetFileSpec().GetFilename().AsCString("<Unknown>"),
309fe6060f1SDimitry Andric line);
3100b57cec5SDimitry Andric
311fe6060f1SDimitry Andric SetSCMatchesByLine(filter, sc_list, m_skip_prologue, s.GetString(), line,
312fe6060f1SDimitry Andric column);
3130b57cec5SDimitry Andric
3140b57cec5SDimitry Andric return Searcher::eCallbackReturnContinue;
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric
GetDepth()3170b57cec5SDimitry Andric lldb::SearchDepth BreakpointResolverFileLine::GetDepth() {
3180b57cec5SDimitry Andric return lldb::eSearchDepthModule;
3190b57cec5SDimitry Andric }
3200b57cec5SDimitry Andric
GetDescription(Stream * s)3210b57cec5SDimitry Andric void BreakpointResolverFileLine::GetDescription(Stream *s) {
322fe6060f1SDimitry Andric s->Printf("file = '%s', line = %u, ",
323fe6060f1SDimitry Andric m_location_spec.GetFileSpec().GetPath().c_str(),
32481ad6265SDimitry Andric m_location_spec.GetLine().value_or(0));
325fe6060f1SDimitry Andric auto column = m_location_spec.GetColumn();
326fe6060f1SDimitry Andric if (column)
327fe6060f1SDimitry Andric s->Printf("column = %u, ", *column);
328fe6060f1SDimitry Andric s->Printf("exact_match = %d", m_location_spec.GetExactMatch());
3290b57cec5SDimitry Andric }
3300b57cec5SDimitry Andric
Dump(Stream * s) const3310b57cec5SDimitry Andric void BreakpointResolverFileLine::Dump(Stream *s) const {}
3320b57cec5SDimitry Andric
3330b57cec5SDimitry Andric lldb::BreakpointResolverSP
CopyForBreakpoint(BreakpointSP & breakpoint)3345ffd83dbSDimitry Andric BreakpointResolverFileLine::CopyForBreakpoint(BreakpointSP &breakpoint) {
3350b57cec5SDimitry Andric lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileLine(
336fe6060f1SDimitry Andric breakpoint, GetOffset(), m_skip_prologue, m_location_spec));
3370b57cec5SDimitry Andric
3380b57cec5SDimitry Andric return ret_sp;
3390b57cec5SDimitry Andric }
340