File: | tools/lldb/source/Breakpoint/BreakpointResolver.cpp |
Warning: | line 146, 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/Core/Address.h" | |||
25 | #include "lldb/Core/ModuleList.h" | |||
26 | #include "lldb/Core/SearchFilter.h" | |||
27 | #include "lldb/Symbol/CompileUnit.h" | |||
28 | #include "lldb/Symbol/Function.h" | |||
29 | #include "lldb/Symbol/SymbolContext.h" | |||
30 | #include "lldb/Target/Target.h" | |||
31 | #include "lldb/Utility/Log.h" | |||
32 | #include "lldb/Utility/Stream.h" | |||
33 | #include "lldb/Utility/StreamString.h" | |||
34 | ||||
35 | using namespace lldb_private; | |||
36 | using namespace lldb; | |||
37 | ||||
38 | //---------------------------------------------------------------------- | |||
39 | // BreakpointResolver: | |||
40 | //---------------------------------------------------------------------- | |||
41 | const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address", | |||
42 | "SymbolName", "SourceRegex", | |||
43 | "Exception", "Unknown"}; | |||
44 | ||||
45 | const char *BreakpointResolver::g_option_names[static_cast<uint32_t>( | |||
46 | BreakpointResolver::OptionNames::LastOptionName)] = { | |||
47 | "AddressOffset", "Exact", "FileName", "Inlines", "Language", | |||
48 | "LineNumber", "ModuleName", "NameMask", "Offset", "Regex", | |||
49 | "SectionName", "SkipPrologue", "SymbolNames"}; | |||
50 | ||||
51 | const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) { | |||
52 | if (type > LastKnownResolverType) | |||
53 | return g_ty_to_name[UnknownResolver]; | |||
54 | ||||
55 | return g_ty_to_name[type]; | |||
56 | } | |||
57 | ||||
58 | BreakpointResolver::ResolverTy | |||
59 | BreakpointResolver::NameToResolverTy(llvm::StringRef name) { | |||
60 | for (size_t i = 0; i < LastKnownResolverType; i++) { | |||
61 | if (name == g_ty_to_name[i]) | |||
62 | return (ResolverTy)i; | |||
63 | } | |||
64 | return UnknownResolver; | |||
65 | } | |||
66 | ||||
67 | BreakpointResolver::BreakpointResolver(Breakpoint *bkpt, | |||
68 | const unsigned char resolverTy, | |||
69 | lldb::addr_t offset) | |||
70 | : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {} | |||
71 | ||||
72 | BreakpointResolver::~BreakpointResolver() {} | |||
73 | ||||
74 | BreakpointResolverSP BreakpointResolver::CreateFromStructuredData( | |||
75 | const StructuredData::Dictionary &resolver_dict, Status &error) { | |||
76 | BreakpointResolverSP result_sp; | |||
77 | if (!resolver_dict.IsValid()) { | |||
| ||||
78 | error.SetErrorString("Can't deserialize from an invalid data object."); | |||
79 | return result_sp; | |||
80 | } | |||
81 | ||||
82 | llvm::StringRef subclass_name; | |||
83 | ||||
84 | bool success = resolver_dict.GetValueForKeyAsString( | |||
85 | GetSerializationSubclassKey(), subclass_name); | |||
86 | ||||
87 | if (!success) { | |||
88 | error.SetErrorStringWithFormat( | |||
89 | "Resolver data missing subclass resolver key"); | |||
90 | return result_sp; | |||
91 | } | |||
92 | ||||
93 | ResolverTy resolver_type = NameToResolverTy(subclass_name); | |||
94 | if (resolver_type == UnknownResolver) { | |||
95 | error.SetErrorStringWithFormatv("Unknown resolver type: {0}.", | |||
96 | subclass_name); | |||
97 | return result_sp; | |||
98 | } | |||
99 | ||||
100 | StructuredData::Dictionary *subclass_options = nullptr; | |||
101 | success = resolver_dict.GetValueForKeyAsDictionary( | |||
102 | GetSerializationSubclassOptionsKey(), subclass_options); | |||
103 | if (!success || !subclass_options || !subclass_options->IsValid()) { | |||
104 | error.SetErrorString("Resolver data missing subclass options key."); | |||
105 | return result_sp; | |||
106 | } | |||
107 | ||||
108 | lldb::addr_t offset; | |||
109 | success = subclass_options->GetValueForKeyAsInteger( | |||
110 | GetKey(OptionNames::Offset), offset); | |||
111 | if (!success) { | |||
112 | error.SetErrorString("Resolver data missing offset options key."); | |||
113 | return result_sp; | |||
114 | } | |||
115 | ||||
116 | BreakpointResolver *resolver; | |||
117 | ||||
118 | switch (resolver_type) { | |||
119 | case FileLineResolver: | |||
120 | resolver = BreakpointResolverFileLine::CreateFromStructuredData( | |||
121 | nullptr, *subclass_options, error); | |||
122 | break; | |||
123 | case AddressResolver: | |||
124 | resolver = BreakpointResolverAddress::CreateFromStructuredData( | |||
125 | nullptr, *subclass_options, error); | |||
126 | break; | |||
127 | case NameResolver: | |||
128 | resolver = BreakpointResolverName::CreateFromStructuredData( | |||
129 | nullptr, *subclass_options, error); | |||
130 | break; | |||
131 | case FileRegexResolver: | |||
132 | resolver = BreakpointResolverFileRegex::CreateFromStructuredData( | |||
133 | nullptr, *subclass_options, error); | |||
134 | break; | |||
135 | case ExceptionResolver: | |||
136 | error.SetErrorString("Exception resolvers are hard."); | |||
137 | break; | |||
138 | default: | |||
139 | llvm_unreachable("Should never get an unresolvable resolver type.")::llvm::llvm_unreachable_internal("Should never get an unresolvable resolver type." , "/build/llvm-toolchain-snapshot-7~svn338205/tools/lldb/source/Breakpoint/BreakpointResolver.cpp" , 139); | |||
140 | } | |||
141 | ||||
142 | if (!error.Success()) { | |||
143 | return result_sp; | |||
144 | } else { | |||
145 | // Add on the global offset option: | |||
146 | resolver->SetOffset(offset); | |||
| ||||
147 | return BreakpointResolverSP(resolver); | |||
148 | } | |||
149 | } | |||
150 | ||||
151 | StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict( | |||
152 | StructuredData::DictionarySP options_dict_sp) { | |||
153 | if (!options_dict_sp || !options_dict_sp->IsValid()) | |||
154 | return StructuredData::DictionarySP(); | |||
155 | ||||
156 | StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary()); | |||
157 | type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetResolverName()); | |||
158 | type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp); | |||
159 | ||||
160 | // Add the m_offset to the dictionary: | |||
161 | options_dict_sp->AddIntegerItem(GetKey(OptionNames::Offset), m_offset); | |||
162 | ||||
163 | return type_dict_sp; | |||
164 | } | |||
165 | ||||
166 | void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) { | |||
167 | m_breakpoint = bkpt; | |||
168 | } | |||
169 | ||||
170 | void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter, | |||
171 | ModuleList &modules) { | |||
172 | filter.SearchInModuleList(*this, modules); | |||
173 | } | |||
174 | ||||
175 | void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) { | |||
176 | filter.Search(*this); | |||
177 | } | |||
178 | ||||
179 | void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter, | |||
180 | SymbolContextList &sc_list, | |||
181 | bool skip_prologue, | |||
182 | llvm::StringRef log_ident) { | |||
183 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS(1u << 5))); | |||
184 | ||||
185 | while (sc_list.GetSize() > 0) { | |||
186 | SymbolContextList tmp_sc_list; | |||
187 | unsigned current_idx = 0; | |||
188 | SymbolContext sc; | |||
189 | bool first_entry = true; | |||
190 | ||||
191 | FileSpec match_file_spec; | |||
192 | FileSpec match_original_file_spec; | |||
193 | uint32_t closest_line_number = UINT32_MAX(4294967295U); | |||
194 | ||||
195 | // Pull out the first entry, and all the others that match its file spec, | |||
196 | // and stuff them in the tmp list. | |||
197 | while (current_idx < sc_list.GetSize()) { | |||
198 | bool matches; | |||
199 | ||||
200 | sc_list.GetContextAtIndex(current_idx, sc); | |||
201 | if (first_entry) { | |||
202 | match_file_spec = sc.line_entry.file; | |||
203 | match_original_file_spec = sc.line_entry.original_file; | |||
204 | matches = true; | |||
205 | first_entry = false; | |||
206 | } else | |||
207 | matches = ((sc.line_entry.file == match_file_spec) || | |||
208 | (sc.line_entry.original_file == match_original_file_spec)); | |||
209 | ||||
210 | if (matches) { | |||
211 | tmp_sc_list.Append(sc); | |||
212 | sc_list.RemoveContextAtIndex(current_idx); | |||
213 | ||||
214 | // ResolveSymbolContext will always return a number that is >= the line | |||
215 | // number you pass in. So the smaller line number is always better. | |||
216 | if (sc.line_entry.line < closest_line_number) | |||
217 | closest_line_number = sc.line_entry.line; | |||
218 | } else | |||
219 | current_idx++; | |||
220 | } | |||
221 | ||||
222 | // Okay, we've found the closest line number match, now throw away all the | |||
223 | // others: | |||
224 | ||||
225 | current_idx = 0; | |||
226 | while (current_idx < tmp_sc_list.GetSize()) { | |||
227 | if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) { | |||
228 | if (sc.line_entry.line != closest_line_number) | |||
229 | tmp_sc_list.RemoveContextAtIndex(current_idx); | |||
230 | else | |||
231 | current_idx++; | |||
232 | } | |||
233 | } | |||
234 | ||||
235 | // Next go through and see if there are line table entries that are | |||
236 | // contiguous, and if so keep only the first of the contiguous range: | |||
237 | ||||
238 | current_idx = 0; | |||
239 | std::map<Block *, lldb::addr_t> blocks_with_breakpoints; | |||
240 | ||||
241 | while (current_idx < tmp_sc_list.GetSize()) { | |||
242 | if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) { | |||
243 | if (blocks_with_breakpoints.find(sc.block) != | |||
244 | blocks_with_breakpoints.end()) | |||
245 | tmp_sc_list.RemoveContextAtIndex(current_idx); | |||
246 | else { | |||
247 | blocks_with_breakpoints.insert(std::pair<Block *, lldb::addr_t>( | |||
248 | sc.block, sc.line_entry.range.GetBaseAddress().GetFileAddress())); | |||
249 | current_idx++; | |||
250 | } | |||
251 | } | |||
252 | } | |||
253 | ||||
254 | // and make breakpoints out of the closest line number match. | |||
255 | ||||
256 | uint32_t tmp_sc_list_size = tmp_sc_list.GetSize(); | |||
257 | ||||
258 | for (uint32_t i = 0; i < tmp_sc_list_size; i++) { | |||
259 | if (tmp_sc_list.GetContextAtIndex(i, sc)) { | |||
260 | Address line_start = sc.line_entry.range.GetBaseAddress(); | |||
261 | if (line_start.IsValid()) { | |||
262 | if (filter.AddressPasses(line_start)) { | |||
263 | // If the line number is before the prologue end, move it there... | |||
264 | bool skipped_prologue = false; | |||
265 | if (skip_prologue) { | |||
266 | if (sc.function) { | |||
267 | Address prologue_addr( | |||
268 | sc.function->GetAddressRange().GetBaseAddress()); | |||
269 | if (prologue_addr.IsValid() && (line_start == prologue_addr)) { | |||
270 | const uint32_t prologue_byte_size = | |||
271 | sc.function->GetPrologueByteSize(); | |||
272 | if (prologue_byte_size) { | |||
273 | prologue_addr.Slide(prologue_byte_size); | |||
274 | ||||
275 | if (filter.AddressPasses(prologue_addr)) { | |||
276 | skipped_prologue = true; | |||
277 | line_start = prologue_addr; | |||
278 | } | |||
279 | } | |||
280 | } | |||
281 | } | |||
282 | } | |||
283 | ||||
284 | BreakpointLocationSP bp_loc_sp(AddLocation(line_start)); | |||
285 | if (log && bp_loc_sp && !m_breakpoint->IsInternal()) { | |||
286 | StreamString s; | |||
287 | bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); | |||
288 | log->Printf("Added location (skipped prologue: %s): %s \n", | |||
289 | skipped_prologue ? "yes" : "no", s.GetData()); | |||
290 | } | |||
291 | } else if (log) { | |||
292 | log->Printf("Breakpoint %s at file address 0x%" PRIx64"l" "x" | |||
293 | " didn't pass the filter.\n", | |||
294 | log_ident.str().c_str(), line_start.GetFileAddress()); | |||
295 | } | |||
296 | } else { | |||
297 | if (log) | |||
298 | log->Printf( | |||
299 | "error: Unable to set breakpoint %s at file address 0x%" PRIx64"l" "x" | |||
300 | "\n", | |||
301 | log_ident.str().c_str(), line_start.GetFileAddress()); | |||
302 | } | |||
303 | } | |||
304 | } | |||
305 | } | |||
306 | } | |||
307 | ||||
308 | BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr, | |||
309 | bool *new_location) { | |||
310 | loc_addr.Slide(m_offset); | |||
311 | return m_breakpoint->AddLocation(loc_addr, new_location); | |||
312 | } | |||
313 | ||||
314 | void BreakpointResolver::SetOffset(lldb::addr_t offset) { | |||
315 | // There may already be an offset, so we are actually adjusting location | |||
316 | // addresses by the difference. | |||
317 | // lldb::addr_t slide = offset - m_offset; | |||
318 | // FIXME: We should go fix up all the already set locations for the new slide. | |||
319 | ||||
320 | m_offset = offset; | |||
321 | } |