File: | tools/lldb/source/Breakpoint/BreakpointResolver.cpp |
Warning: | line 152, column 5 Called C++ object pointer is uninitialized |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- BreakpointResolver.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/BreakpointResolver.h" | |||
11 | ||||
12 | // C Includes | |||
13 | // C++ Includes | |||
14 | // Other libraries and framework includes | |||
15 | // Project includes | |||
16 | #include "lldb/Breakpoint/Breakpoint.h" | |||
17 | #include "lldb/Breakpoint/BreakpointLocation.h" | |||
18 | // Have to include the other breakpoint resolver types here so the static | |||
19 | // create from StructuredData can call them. | |||
20 | #include "lldb/Breakpoint/BreakpointResolverAddress.h" | |||
21 | #include "lldb/Breakpoint/BreakpointResolverFileLine.h" | |||
22 | #include "lldb/Breakpoint/BreakpointResolverFileRegex.h" | |||
23 | #include "lldb/Breakpoint/BreakpointResolverName.h" | |||
24 | #include "lldb/Breakpoint/BreakpointResolverScripted.h" | |||
25 | #include "lldb/Core/Address.h" | |||
26 | #include "lldb/Core/ModuleList.h" | |||
27 | #include "lldb/Core/SearchFilter.h" | |||
28 | #include "lldb/Symbol/CompileUnit.h" | |||
29 | #include "lldb/Symbol/Function.h" | |||
30 | #include "lldb/Symbol/SymbolContext.h" | |||
31 | #include "lldb/Target/Target.h" | |||
32 | #include "lldb/Utility/Log.h" | |||
33 | #include "lldb/Utility/Stream.h" | |||
34 | #include "lldb/Utility/StreamString.h" | |||
35 | ||||
36 | using namespace lldb_private; | |||
37 | using namespace lldb; | |||
38 | ||||
39 | //---------------------------------------------------------------------- | |||
40 | // BreakpointResolver: | |||
41 | //---------------------------------------------------------------------- | |||
42 | const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address", | |||
43 | "SymbolName", "SourceRegex", | |||
44 | "Exception", "Unknown"}; | |||
45 | ||||
46 | const char *BreakpointResolver::g_option_names[static_cast<uint32_t>( | |||
47 | BreakpointResolver::OptionNames::LastOptionName)] = { | |||
48 | "AddressOffset", "Exact", "FileName", "Inlines", "Language", | |||
49 | "LineNumber", "Column", "ModuleName", "NameMask", "Offset", | |||
50 | "PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth", | |||
51 | "SkipPrologue", "SymbolNames"}; | |||
52 | ||||
53 | const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) { | |||
54 | if (type > LastKnownResolverType) | |||
55 | return g_ty_to_name[UnknownResolver]; | |||
56 | ||||
57 | return g_ty_to_name[type]; | |||
58 | } | |||
59 | ||||
60 | BreakpointResolver::ResolverTy | |||
61 | BreakpointResolver::NameToResolverTy(llvm::StringRef name) { | |||
62 | for (size_t i = 0; i < LastKnownResolverType; i++) { | |||
63 | if (name == g_ty_to_name[i]) | |||
64 | return (ResolverTy)i; | |||
65 | } | |||
66 | return UnknownResolver; | |||
67 | } | |||
68 | ||||
69 | BreakpointResolver::BreakpointResolver(Breakpoint *bkpt, | |||
70 | const unsigned char resolverTy, | |||
71 | lldb::addr_t offset) | |||
72 | : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {} | |||
73 | ||||
74 | BreakpointResolver::~BreakpointResolver() {} | |||
75 | ||||
76 | BreakpointResolverSP BreakpointResolver::CreateFromStructuredData( | |||
77 | const StructuredData::Dictionary &resolver_dict, Status &error) { | |||
78 | BreakpointResolverSP result_sp; | |||
79 | if (!resolver_dict.IsValid()) { | |||
| ||||
80 | error.SetErrorString("Can't deserialize from an invalid data object."); | |||
81 | return result_sp; | |||
82 | } | |||
83 | ||||
84 | llvm::StringRef subclass_name; | |||
85 | ||||
86 | bool success = resolver_dict.GetValueForKeyAsString( | |||
87 | GetSerializationSubclassKey(), subclass_name); | |||
88 | ||||
89 | if (!success) { | |||
90 | error.SetErrorStringWithFormat( | |||
91 | "Resolver data missing subclass resolver key"); | |||
92 | return result_sp; | |||
93 | } | |||
94 | ||||
95 | ResolverTy resolver_type = NameToResolverTy(subclass_name); | |||
96 | if (resolver_type == UnknownResolver) { | |||
97 | error.SetErrorStringWithFormatv("Unknown resolver type: {0}.", | |||
98 | subclass_name); | |||
99 | return result_sp; | |||
100 | } | |||
101 | ||||
102 | StructuredData::Dictionary *subclass_options = nullptr; | |||
103 | success = resolver_dict.GetValueForKeyAsDictionary( | |||
104 | GetSerializationSubclassOptionsKey(), subclass_options); | |||
105 | if (!success || !subclass_options || !subclass_options->IsValid()) { | |||
106 | error.SetErrorString("Resolver data missing subclass options key."); | |||
107 | return result_sp; | |||
108 | } | |||
109 | ||||
110 | lldb::addr_t offset; | |||
111 | success = subclass_options->GetValueForKeyAsInteger( | |||
112 | GetKey(OptionNames::Offset), offset); | |||
113 | if (!success) { | |||
114 | error.SetErrorString("Resolver data missing offset options key."); | |||
115 | return result_sp; | |||
116 | } | |||
117 | ||||
118 | BreakpointResolver *resolver; | |||
119 | ||||
120 | switch (resolver_type) { | |||
121 | case FileLineResolver: | |||
122 | resolver = BreakpointResolverFileLine::CreateFromStructuredData( | |||
123 | nullptr, *subclass_options, error); | |||
124 | break; | |||
125 | case AddressResolver: | |||
126 | resolver = BreakpointResolverAddress::CreateFromStructuredData( | |||
127 | nullptr, *subclass_options, error); | |||
128 | break; | |||
129 | case NameResolver: | |||
130 | resolver = BreakpointResolverName::CreateFromStructuredData( | |||
131 | nullptr, *subclass_options, error); | |||
132 | break; | |||
133 | case FileRegexResolver: | |||
134 | resolver = BreakpointResolverFileRegex::CreateFromStructuredData( | |||
135 | nullptr, *subclass_options, error); | |||
136 | break; | |||
137 | case PythonResolver: | |||
138 | resolver = BreakpointResolverScripted::CreateFromStructuredData( | |||
139 | nullptr, *subclass_options, error); | |||
140 | break; | |||
141 | case ExceptionResolver: | |||
142 | error.SetErrorString("Exception resolvers are hard."); | |||
143 | break; | |||
144 | default: | |||
145 | llvm_unreachable("Should never get an unresolvable resolver type.")::llvm::llvm_unreachable_internal("Should never get an unresolvable resolver type." , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Breakpoint/BreakpointResolver.cpp" , 145); | |||
146 | } | |||
147 | ||||
148 | if (!error.Success()) { | |||
149 | return result_sp; | |||
150 | } else { | |||
151 | // Add on the global offset option: | |||
152 | resolver->SetOffset(offset); | |||
| ||||
153 | return BreakpointResolverSP(resolver); | |||
154 | } | |||
155 | } | |||
156 | ||||
157 | StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict( | |||
158 | StructuredData::DictionarySP options_dict_sp) { | |||
159 | if (!options_dict_sp || !options_dict_sp->IsValid()) | |||
160 | return StructuredData::DictionarySP(); | |||
161 | ||||
162 | StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary()); | |||
163 | type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetResolverName()); | |||
164 | type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp); | |||
165 | ||||
166 | // Add the m_offset to the dictionary: | |||
167 | options_dict_sp->AddIntegerItem(GetKey(OptionNames::Offset), m_offset); | |||
168 | ||||
169 | return type_dict_sp; | |||
170 | } | |||
171 | ||||
172 | void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) { | |||
173 | m_breakpoint = bkpt; | |||
174 | NotifyBreakpointSet(); | |||
175 | } | |||
176 | ||||
177 | void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter, | |||
178 | ModuleList &modules) { | |||
179 | filter.SearchInModuleList(*this, modules); | |||
180 | } | |||
181 | ||||
182 | void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) { | |||
183 | filter.Search(*this); | |||
184 | } | |||
185 | ||||
186 | namespace { | |||
187 | struct SourceLoc { | |||
188 | uint32_t line = UINT32_MAX(4294967295U); | |||
189 | uint32_t column; | |||
190 | SourceLoc(uint32_t l, uint32_t c) : line(l), column(c ? c : UINT32_MAX(4294967295U)) {} | |||
191 | SourceLoc(const SymbolContext &sc) | |||
192 | : line(sc.line_entry.line), | |||
193 | column(sc.line_entry.column ? sc.line_entry.column : UINT32_MAX(4294967295U)) {} | |||
194 | }; | |||
195 | ||||
196 | bool operator<(const SourceLoc a, const SourceLoc b) { | |||
197 | if (a.line < b.line) | |||
198 | return true; | |||
199 | if (a.line > b.line) | |||
200 | return false; | |||
201 | uint32_t a_col = a.column ? a.column : UINT32_MAX(4294967295U); | |||
202 | uint32_t b_col = b.column ? b.column : UINT32_MAX(4294967295U); | |||
203 | return a_col < b_col; | |||
204 | } | |||
205 | } // namespace | |||
206 | ||||
207 | void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter, | |||
208 | SymbolContextList &sc_list, | |||
209 | bool skip_prologue, | |||
210 | llvm::StringRef log_ident, | |||
211 | uint32_t line, uint32_t column) { | |||
212 | llvm::SmallVector<SymbolContext, 16> all_scs; | |||
213 | for (uint32_t i = 0; i < sc_list.GetSize(); ++i) | |||
214 | all_scs.push_back(sc_list[i]); | |||
215 | ||||
216 | while (all_scs.size()) { | |||
217 | uint32_t closest_line = UINT32_MAX(4294967295U); | |||
218 | ||||
219 | // Move all the elements with a matching file spec to the end. | |||
220 | auto &match = all_scs[0]; | |||
221 | auto worklist_begin = std::partition( | |||
222 | all_scs.begin(), all_scs.end(), [&](const SymbolContext &sc) { | |||
223 | if (sc.line_entry.file == match.line_entry.file || | |||
224 | sc.line_entry.original_file == match.line_entry.original_file) { | |||
225 | // When a match is found, keep track of the smallest line number. | |||
226 | closest_line = std::min(closest_line, sc.line_entry.line); | |||
227 | return false; | |||
228 | } | |||
229 | return true; | |||
230 | }); | |||
231 | ||||
232 | // (worklist_begin, worklist_end) now contains all entries for one filespec. | |||
233 | auto worklist_end = all_scs.end(); | |||
234 | ||||
235 | if (column) { | |||
236 | // If a column was requested, do a more precise match and only | |||
237 | // return the first location that comes after or at the | |||
238 | // requested location. | |||
239 | SourceLoc requested(line, column); | |||
240 | // First, filter out all entries left of the requested column. | |||
241 | worklist_end = std::remove_if( | |||
242 | worklist_begin, worklist_end, | |||
243 | [&](const SymbolContext &sc) { return SourceLoc(sc) < requested; }); | |||
244 | // Sort the remaining entries by (line, column). | |||
245 | std::sort(worklist_begin, worklist_end, | |||
246 | [](const SymbolContext &a, const SymbolContext &b) { | |||
247 | return SourceLoc(a) < SourceLoc(b); | |||
248 | }); | |||
249 | ||||
250 | // Filter out all locations with a source location after the closest match. | |||
251 | if (worklist_begin != worklist_end) | |||
252 | worklist_end = std::remove_if( | |||
253 | worklist_begin, worklist_end, [&](const SymbolContext &sc) { | |||
254 | return SourceLoc(*worklist_begin) < SourceLoc(sc); | |||
255 | }); | |||
256 | } else { | |||
257 | // Remove all entries with a larger line number. | |||
258 | // ResolveSymbolContext will always return a number that is >= | |||
259 | // the line number you pass in. So the smaller line number is | |||
260 | // always better. | |||
261 | worklist_end = std::remove_if(worklist_begin, worklist_end, | |||
262 | [&](const SymbolContext &sc) { | |||
263 | return closest_line != sc.line_entry.line; | |||
264 | }); | |||
265 | } | |||
266 | ||||
267 | // Sort by file address. | |||
268 | std::sort(worklist_begin, worklist_end, | |||
269 | [](const SymbolContext &a, const SymbolContext &b) { | |||
270 | return a.line_entry.range.GetBaseAddress().GetFileAddress() < | |||
271 | b.line_entry.range.GetBaseAddress().GetFileAddress(); | |||
272 | }); | |||
273 | ||||
274 | // Go through and see if there are line table entries that are | |||
275 | // contiguous, and if so keep only the first of the contiguous range. | |||
276 | // We do this by picking the first location in each lexical block. | |||
277 | llvm::SmallDenseSet<Block *, 8> blocks_with_breakpoints; | |||
278 | for (auto first = worklist_begin; first != worklist_end; ++first) { | |||
279 | assert(!blocks_with_breakpoints.count(first->block))((!blocks_with_breakpoints.count(first->block)) ? static_cast <void> (0) : __assert_fail ("!blocks_with_breakpoints.count(first->block)" , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Breakpoint/BreakpointResolver.cpp" , 279, __PRETTY_FUNCTION__)); | |||
280 | blocks_with_breakpoints.insert(first->block); | |||
281 | worklist_end = | |||
282 | std::remove_if(std::next(first), worklist_end, | |||
283 | [&](const SymbolContext &sc) { | |||
284 | return blocks_with_breakpoints.count(sc.block); | |||
285 | }); | |||
286 | } | |||
287 | ||||
288 | // Make breakpoints out of the closest line number match. | |||
289 | for (auto &sc : llvm::make_range(worklist_begin, worklist_end)) | |||
290 | AddLocation(filter, sc, skip_prologue, log_ident); | |||
291 | ||||
292 | // Remove all contexts processed by this iteration. | |||
293 | all_scs.erase(worklist_begin, all_scs.end()); | |||
294 | } | |||
295 | } | |||
296 | ||||
297 | void BreakpointResolver::AddLocation(SearchFilter &filter, | |||
298 | const SymbolContext &sc, | |||
299 | bool skip_prologue, | |||
300 | llvm::StringRef log_ident) { | |||
301 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS(1u << 5))); | |||
302 | Address line_start = sc.line_entry.range.GetBaseAddress(); | |||
303 | if (!line_start.IsValid()) { | |||
304 | if (log) | |||
305 | log->Printf("error: Unable to set breakpoint %s at file address " | |||
306 | "0x%" PRIx64"l" "x" "\n", | |||
307 | log_ident.str().c_str(), line_start.GetFileAddress()); | |||
308 | return; | |||
309 | } | |||
310 | ||||
311 | if (!filter.AddressPasses(line_start)) { | |||
312 | if (log) | |||
313 | log->Printf("Breakpoint %s at file address 0x%" PRIx64"l" "x" | |||
314 | " didn't pass the filter.\n", | |||
315 | log_ident.str().c_str(), line_start.GetFileAddress()); | |||
316 | } | |||
317 | ||||
318 | // If the line number is before the prologue end, move it there... | |||
319 | bool skipped_prologue = false; | |||
320 | if (skip_prologue && sc.function) { | |||
321 | Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress()); | |||
322 | if (prologue_addr.IsValid() && (line_start == prologue_addr)) { | |||
323 | const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize(); | |||
324 | if (prologue_byte_size) { | |||
325 | prologue_addr.Slide(prologue_byte_size); | |||
326 | ||||
327 | if (filter.AddressPasses(prologue_addr)) { | |||
328 | skipped_prologue = true; | |||
329 | line_start = prologue_addr; | |||
330 | } | |||
331 | } | |||
332 | } | |||
333 | } | |||
334 | ||||
335 | BreakpointLocationSP bp_loc_sp(AddLocation(line_start)); | |||
336 | if (log && bp_loc_sp && !m_breakpoint->IsInternal()) { | |||
337 | StreamString s; | |||
338 | bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); | |||
339 | log->Printf("Added location (skipped prologue: %s): %s \n", | |||
340 | skipped_prologue ? "yes" : "no", s.GetData()); | |||
341 | } | |||
342 | } | |||
343 | ||||
344 | BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr, | |||
345 | bool *new_location) { | |||
346 | loc_addr.Slide(m_offset); | |||
347 | return m_breakpoint->AddLocation(loc_addr, new_location); | |||
348 | } | |||
349 | ||||
350 | void BreakpointResolver::SetOffset(lldb::addr_t offset) { | |||
351 | // There may already be an offset, so we are actually adjusting location | |||
352 | // addresses by the difference. | |||
353 | // lldb::addr_t slide = offset - m_offset; | |||
354 | // FIXME: We should go fix up all the already set locations for the new | |||
355 | // slide. | |||
356 | ||||
357 | m_offset = offset; | |||
358 | } |