]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Breakpoint / BreakpointResolverFileLine.cpp
1 //===-- BreakpointResolverFileLine.cpp --------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Breakpoint/BreakpointResolverFileLine.h"
11
12 #include "lldb/Breakpoint/BreakpointLocation.h"
13 #include "lldb/Core/Module.h"
14 #include "lldb/Symbol/CompileUnit.h"
15 #include "lldb/Symbol/Function.h"
16 #include "lldb/Utility/Log.h"
17 #include "lldb/Utility/StreamString.h"
18
19 using namespace lldb;
20 using namespace lldb_private;
21
22 //----------------------------------------------------------------------
23 // BreakpointResolverFileLine:
24 //----------------------------------------------------------------------
25 BreakpointResolverFileLine::BreakpointResolverFileLine(
26     Breakpoint *bkpt, const FileSpec &file_spec, uint32_t line_no,
27     uint32_t column, lldb::addr_t offset, bool check_inlines,
28     bool skip_prologue, bool exact_match)
29     : BreakpointResolver(bkpt, BreakpointResolver::FileLineResolver, offset),
30       m_file_spec(file_spec), m_line_number(line_no), m_column(column),
31       m_inlines(check_inlines), m_skip_prologue(skip_prologue),
32       m_exact_match(exact_match) {}
33
34 BreakpointResolverFileLine::~BreakpointResolverFileLine() {}
35
36 BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData(
37     Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
38     Status &error) {
39   llvm::StringRef filename;
40   uint32_t line_no;
41   uint32_t column;
42   bool check_inlines;
43   bool skip_prologue;
44   bool exact_match;
45   bool success;
46
47   lldb::addr_t offset = 0;
48
49   success = options_dict.GetValueForKeyAsString(GetKey(OptionNames::FileName),
50                                                 filename);
51   if (!success) {
52     error.SetErrorString("BRFL::CFSD: Couldn't find filename entry.");
53     return nullptr;
54   }
55
56   success = options_dict.GetValueForKeyAsInteger(
57       GetKey(OptionNames::LineNumber), line_no);
58   if (!success) {
59     error.SetErrorString("BRFL::CFSD: Couldn't find line number entry.");
60     return nullptr;
61   }
62
63   success =
64       options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Column), column);
65   if (!success) {
66     // Backwards compatibility.
67     column = 0;
68   }
69
70   success = options_dict.GetValueForKeyAsBoolean(GetKey(OptionNames::Inlines),
71                                                  check_inlines);
72   if (!success) {
73     error.SetErrorString("BRFL::CFSD: Couldn't find check inlines entry.");
74     return nullptr;
75   }
76
77   success = options_dict.GetValueForKeyAsBoolean(
78       GetKey(OptionNames::SkipPrologue), skip_prologue);
79   if (!success) {
80     error.SetErrorString("BRFL::CFSD: Couldn't find skip prologue entry.");
81     return nullptr;
82   }
83
84   success = options_dict.GetValueForKeyAsBoolean(
85       GetKey(OptionNames::ExactMatch), exact_match);
86   if (!success) {
87     error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
88     return nullptr;
89   }
90
91   FileSpec file_spec(filename);
92
93   return new BreakpointResolverFileLine(bkpt, file_spec, line_no, column,
94                                         offset, check_inlines, skip_prologue,
95                                         exact_match);
96 }
97
98 StructuredData::ObjectSP
99 BreakpointResolverFileLine::SerializeToStructuredData() {
100   StructuredData::DictionarySP options_dict_sp(
101       new StructuredData::Dictionary());
102
103   options_dict_sp->AddStringItem(GetKey(OptionNames::FileName),
104                                  m_file_spec.GetPath());
105   options_dict_sp->AddIntegerItem(GetKey(OptionNames::LineNumber),
106                                   m_line_number);
107   options_dict_sp->AddIntegerItem(GetKey(OptionNames::Column),
108                                   m_column);
109   options_dict_sp->AddBooleanItem(GetKey(OptionNames::Inlines), m_inlines);
110   options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
111                                   m_skip_prologue);
112   options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
113                                   m_exact_match);
114
115   return WrapOptionsDict(options_dict_sp);
116 }
117
118 // Filter the symbol context list to remove contexts where the line number was
119 // moved into a new function. We do this conservatively, so if e.g. we cannot
120 // resolve the function in the context (which can happen in case of line-table-
121 // only debug info), we leave the context as is. The trickiest part here is
122 // handling inlined functions -- in this case we need to make sure we look at
123 // the declaration line of the inlined function, NOT the function it was
124 // inlined into.
125 void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list,
126                                                 bool is_relative) {
127   if (m_exact_match)
128     return; // Nothing to do. Contexts are precise.
129
130   llvm::StringRef relative_path;
131   if (is_relative)
132     relative_path = m_file_spec.GetDirectory().GetStringRef();
133
134   Log * log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
135   for(uint32_t i = 0; i < sc_list.GetSize(); ++i) {
136     SymbolContext sc;
137     sc_list.GetContextAtIndex(i, sc);
138     if (is_relative) {
139       // If the path was relative, make sure any matches match as long as the
140       // relative parts of the path match the path from support files
141       auto sc_dir = sc.line_entry.file.GetDirectory().GetStringRef();
142       if (!sc_dir.endswith(relative_path)) {
143         // We had a relative path specified and the relative directory doesn't
144         // match so remove this one
145         LLDB_LOG(log, "removing not matching relative path {0} since it "
146                 "doesn't end with {1}", sc_dir, relative_path);
147         sc_list.RemoveContextAtIndex(i);
148         --i;
149         continue;
150       }
151     }
152
153     if (!sc.block)
154       continue;
155
156     FileSpec file;
157     uint32_t line;
158     const Block *inline_block = sc.block->GetContainingInlinedBlock();
159     if (inline_block) {
160       const Declaration &inline_declaration = inline_block->GetInlinedFunctionInfo()->GetDeclaration();
161       if (!inline_declaration.IsValid())
162         continue;
163       file = inline_declaration.GetFile();
164       line = inline_declaration.GetLine();
165     } else if (sc.function)
166       sc.function->GetStartLineSourceInfo(file, line);
167     else
168       continue;
169
170     if (file != sc.line_entry.file) {
171       LLDB_LOG(log, "unexpected symbol context file {0}", sc.line_entry.file);
172       continue;
173     }
174
175     // Compare the requested line number with the line of the function
176     // declaration. In case of a function declared as:
177     //
178     // int
179     // foo()
180     // {
181     //   ...
182     //
183     // the compiler will set the declaration line to the "foo" line, which is
184     // the reason why we have -1 here. This can fail in case of two inline
185     // functions defined back-to-back:
186     //
187     // inline int foo1() { ... }
188     // inline int foo2() { ... }
189     //
190     // but that's the best we can do for now.
191     // One complication, if the line number returned from GetStartLineSourceInfo
192     // is 0, then we can't do this calculation.  That can happen if
193     // GetStartLineSourceInfo gets an error, or if the first line number in
194     // the function really is 0 - which happens for some languages.
195     const int decl_line_is_too_late_fudge = 1;
196     if (line && m_line_number < line - decl_line_is_too_late_fudge) {
197       LLDB_LOG(log, "removing symbol context at {0}:{1}", file, line);
198       sc_list.RemoveContextAtIndex(i);
199       --i;
200     }
201   }
202 }
203
204 Searcher::CallbackReturn
205 BreakpointResolverFileLine::SearchCallback(SearchFilter &filter,
206                                            SymbolContext &context,
207                                            Address *addr, bool containing) {
208   SymbolContextList sc_list;
209
210   assert(m_breakpoint != NULL);
211
212   // There is a tricky bit here.  You can have two compilation units that
213   // #include the same file, and in one of them the function at m_line_number
214   // is used (and so code and a line entry for it is generated) but in the
215   // other it isn't.  If we considered the CU's independently, then in the
216   // second inclusion, we'd move the breakpoint to the next function that
217   // actually generated code in the header file.  That would end up being
218   // confusing.  So instead, we do the CU iterations by hand here, then scan
219   // through the complete list of matches, and figure out the closest line
220   // number match, and only set breakpoints on that match.
221
222   // Note also that if file_spec only had a file name and not a directory,
223   // there may be many different file spec's in the resultant list.  The
224   // closest line match for one will not be right for some totally different
225   // file.  So we go through the match list and pull out the sets that have the
226   // same file spec in their line_entry and treat each set separately.
227
228   FileSpec search_file_spec = m_file_spec;
229   const bool is_relative = m_file_spec.IsRelative();
230   if (is_relative)
231     search_file_spec.GetDirectory().Clear();
232
233   const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
234   for (size_t i = 0; i < num_comp_units; i++) {
235     CompUnitSP cu_sp(context.module_sp->GetCompileUnitAtIndex(i));
236     if (cu_sp) {
237       if (filter.CompUnitPasses(*cu_sp))
238         cu_sp->ResolveSymbolContext(search_file_spec, m_line_number, m_inlines,
239                                     m_exact_match, eSymbolContextEverything,
240                                     sc_list);
241     }
242   }
243
244   FilterContexts(sc_list, is_relative);
245
246   StreamString s;
247   s.Printf("for %s:%d ", m_file_spec.GetFilename().AsCString("<Unknown>"),
248            m_line_number);
249
250   SetSCMatchesByLine(filter, sc_list, m_skip_prologue, s.GetString(),
251                      m_line_number, m_column);
252
253   return Searcher::eCallbackReturnContinue;
254 }
255
256 lldb::SearchDepth BreakpointResolverFileLine::GetDepth() {
257   return lldb::eSearchDepthModule;
258 }
259
260 void BreakpointResolverFileLine::GetDescription(Stream *s) {
261   s->Printf("file = '%s', line = %u, ", m_file_spec.GetPath().c_str(),
262             m_line_number);
263   if (m_column)
264     s->Printf("column = %u, ", m_column);
265   s->Printf("exact_match = %d", m_exact_match);
266 }
267
268 void BreakpointResolverFileLine::Dump(Stream *s) const {}
269
270 lldb::BreakpointResolverSP
271 BreakpointResolverFileLine::CopyForBreakpoint(Breakpoint &breakpoint) {
272   lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileLine(
273       &breakpoint, m_file_spec, m_line_number, m_column, m_offset, m_inlines,
274       m_skip_prologue, m_exact_match));
275
276   return ret_sp;
277 }