/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/SearchFilter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- SearchFilter.cpp --------------------------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "lldb/Core/SearchFilter.h" |
10 | | |
11 | | #include "lldb/Breakpoint/Breakpoint.h" |
12 | | #include "lldb/Core/Module.h" |
13 | | #include "lldb/Core/ModuleList.h" |
14 | | #include "lldb/Symbol/CompileUnit.h" |
15 | | #include "lldb/Symbol/SymbolContext.h" |
16 | | #include "lldb/Symbol/SymbolFile.h" |
17 | | #include "lldb/Target/Target.h" |
18 | | #include "lldb/Utility/ConstString.h" |
19 | | #include "lldb/Utility/Status.h" |
20 | | #include "lldb/Utility/Stream.h" |
21 | | #include "lldb/lldb-enumerations.h" |
22 | | |
23 | | #include "llvm/ADT/StringRef.h" |
24 | | #include "llvm/Support/ErrorHandling.h" |
25 | | |
26 | | #include <memory> |
27 | | #include <mutex> |
28 | | #include <string> |
29 | | |
30 | | #include <cinttypes> |
31 | | #include <cstring> |
32 | | |
33 | | namespace lldb_private { |
34 | | class Address; |
35 | | } |
36 | | namespace lldb_private { |
37 | | class Function; |
38 | | } |
39 | | |
40 | | using namespace lldb; |
41 | | using namespace lldb_private; |
42 | | |
43 | | const char *SearchFilter::g_ty_to_name[] = {"Unconstrained", "Exception", |
44 | | "Module", "Modules", |
45 | | "ModulesAndCU", "Unknown"}; |
46 | | |
47 | | const char |
48 | | *SearchFilter::g_option_names[SearchFilter::OptionNames::LastOptionName] = { |
49 | | "ModuleList", "CUList"}; |
50 | | |
51 | 51 | const char *SearchFilter::FilterTyToName(enum FilterTy type) { |
52 | 51 | if (type > LastKnownFilterType) |
53 | 0 | return g_ty_to_name[UnknownFilter]; |
54 | | |
55 | 51 | return g_ty_to_name[type]; |
56 | 51 | } |
57 | | |
58 | 19 | SearchFilter::FilterTy SearchFilter::NameToFilterTy(llvm::StringRef name) { |
59 | 42 | for (size_t i = 0; i <= LastKnownFilterType; i++23 ) { |
60 | 42 | if (name == g_ty_to_name[i]) |
61 | 19 | return (FilterTy)i; |
62 | 42 | } |
63 | 0 | return UnknownFilter; |
64 | 19 | } |
65 | | |
66 | 22.5k | Searcher::Searcher() = default; |
67 | | |
68 | 22.4k | Searcher::~Searcher() = default; |
69 | | |
70 | 0 | void Searcher::GetDescription(Stream *s) {} |
71 | | |
72 | | SearchFilter::SearchFilter(const TargetSP &target_sp, unsigned char filterType) |
73 | 15.8k | : m_target_sp(target_sp), SubclassID(filterType) {} |
74 | | |
75 | 15.7k | SearchFilter::~SearchFilter() = default; |
76 | | |
77 | | SearchFilterSP SearchFilter::CreateFromStructuredData( |
78 | | const lldb::TargetSP& target_sp, |
79 | | const StructuredData::Dictionary &filter_dict, |
80 | 19 | Status &error) { |
81 | 19 | SearchFilterSP result_sp; |
82 | 19 | if (!filter_dict.IsValid()) { |
83 | 0 | error.SetErrorString("Can't deserialize from an invalid data object."); |
84 | 0 | return result_sp; |
85 | 0 | } |
86 | | |
87 | 19 | llvm::StringRef subclass_name; |
88 | | |
89 | 19 | bool success = filter_dict.GetValueForKeyAsString( |
90 | 19 | GetSerializationSubclassKey(), subclass_name); |
91 | 19 | if (!success) { |
92 | 0 | error.SetErrorString("Filter data missing subclass key"); |
93 | 0 | return result_sp; |
94 | 0 | } |
95 | | |
96 | 19 | FilterTy filter_type = NameToFilterTy(subclass_name); |
97 | 19 | if (filter_type == UnknownFilter) { |
98 | 0 | error.SetErrorStringWithFormatv("Unknown filter type: {0}.", subclass_name); |
99 | 0 | return result_sp; |
100 | 0 | } |
101 | | |
102 | 19 | StructuredData::Dictionary *subclass_options = nullptr; |
103 | 19 | success = filter_dict.GetValueForKeyAsDictionary( |
104 | 19 | GetSerializationSubclassOptionsKey(), subclass_options); |
105 | 19 | if (!success || !subclass_options || !subclass_options->IsValid()) { |
106 | 0 | error.SetErrorString("Filter data missing subclass options key."); |
107 | 0 | return result_sp; |
108 | 0 | } |
109 | | |
110 | 19 | switch (filter_type) { |
111 | 13 | case Unconstrained: |
112 | 13 | result_sp = SearchFilterForUnconstrainedSearches::CreateFromStructuredData( |
113 | 13 | target_sp, *subclass_options, error); |
114 | 13 | break; |
115 | 0 | case ByModule: |
116 | 0 | result_sp = SearchFilterByModule::CreateFromStructuredData( |
117 | 0 | target_sp, *subclass_options, error); |
118 | 0 | break; |
119 | 1 | case ByModules: |
120 | 1 | result_sp = SearchFilterByModuleList::CreateFromStructuredData( |
121 | 1 | target_sp, *subclass_options, error); |
122 | 1 | break; |
123 | 5 | case ByModulesAndCU: |
124 | 5 | result_sp = SearchFilterByModuleListAndCU::CreateFromStructuredData( |
125 | 5 | target_sp, *subclass_options, error); |
126 | 5 | break; |
127 | 0 | case Exception: |
128 | 0 | error.SetErrorString("Can't serialize exception breakpoints yet."); |
129 | 0 | break; |
130 | 0 | default: |
131 | 0 | llvm_unreachable("Should never get an uresolvable filter type."); |
132 | 19 | } |
133 | | |
134 | 19 | return result_sp; |
135 | 19 | } |
136 | | |
137 | 0 | bool SearchFilter::ModulePasses(const FileSpec &spec) { return true; } |
138 | | |
139 | 0 | bool SearchFilter::ModulePasses(const ModuleSP &module_sp) { return true; } |
140 | | |
141 | 7.45k | bool SearchFilter::AddressPasses(Address &address) { return true; } |
142 | | |
143 | 0 | bool SearchFilter::CompUnitPasses(FileSpec &fileSpec) { return true; } |
144 | | |
145 | 4.30k | bool SearchFilter::CompUnitPasses(CompileUnit &compUnit) { return true; } |
146 | | |
147 | 3 | bool SearchFilter::FunctionPasses(Function &function) { |
148 | | // This is a slightly cheesy job, but since we don't have finer grained |
149 | | // filters yet, just checking that the start address passes is probably |
150 | | // good enough for the base class behavior. |
151 | 3 | Address addr = function.GetAddressRange().GetBaseAddress(); |
152 | 3 | return AddressPasses(addr); |
153 | 3 | } |
154 | | |
155 | | |
156 | 31.6k | uint32_t SearchFilter::GetFilterRequiredItems() { |
157 | 31.6k | return (lldb::SymbolContextItem)0; |
158 | 31.6k | } |
159 | | |
160 | 299 | void SearchFilter::GetDescription(Stream *s) {} |
161 | | |
162 | 0 | void SearchFilter::Dump(Stream *s) const {} |
163 | | |
164 | 15 | lldb::SearchFilterSP SearchFilter::CreateCopy(lldb::TargetSP& target_sp) { |
165 | 15 | SearchFilterSP ret_sp = DoCreateCopy(); |
166 | 15 | ret_sp->SetTarget(target_sp); |
167 | 15 | return ret_sp; |
168 | 15 | } |
169 | | |
170 | | // Helper functions for serialization. |
171 | | |
172 | | StructuredData::DictionarySP |
173 | 51 | SearchFilter::WrapOptionsDict(StructuredData::DictionarySP options_dict_sp) { |
174 | 51 | if (!options_dict_sp || !options_dict_sp->IsValid()) |
175 | 0 | return StructuredData::DictionarySP(); |
176 | | |
177 | 51 | auto type_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
178 | 51 | type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetFilterName()); |
179 | 51 | type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp); |
180 | | |
181 | 51 | return type_dict_sp; |
182 | 51 | } |
183 | | |
184 | | void SearchFilter::SerializeFileSpecList( |
185 | | StructuredData::DictionarySP &options_dict_sp, OptionNames name, |
186 | 33 | FileSpecList &file_list) { |
187 | 33 | size_t num_modules = file_list.GetSize(); |
188 | | |
189 | | // Don't serialize empty lists. |
190 | 33 | if (num_modules == 0) |
191 | 7 | return; |
192 | | |
193 | 26 | auto module_array_sp = std::make_shared<StructuredData::Array>(); |
194 | 71 | for (size_t i = 0; i < num_modules; i++45 ) { |
195 | 45 | module_array_sp->AddItem(std::make_shared<StructuredData::String>( |
196 | 45 | file_list.GetFileSpecAtIndex(i).GetPath())); |
197 | 45 | } |
198 | 26 | options_dict_sp->AddItem(GetKey(name), module_array_sp); |
199 | 26 | } |
200 | | |
201 | | // UTILITY Functions to help iterate down through the elements of the |
202 | | // SymbolContext. |
203 | | |
204 | 6.06k | void SearchFilter::Search(Searcher &searcher) { |
205 | 6.06k | SymbolContext empty_sc; |
206 | | |
207 | 6.06k | if (!m_target_sp) |
208 | 1 | return; |
209 | 6.06k | empty_sc.target_sp = m_target_sp; |
210 | | |
211 | 6.06k | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
212 | 4.37k | searcher.SearchCallback(*this, empty_sc, nullptr); |
213 | 4.37k | return; |
214 | 4.37k | } |
215 | | |
216 | 1.69k | DoModuleIteration(empty_sc, searcher); |
217 | 1.69k | } |
218 | | |
219 | 9.19k | void SearchFilter::SearchInModuleList(Searcher &searcher, ModuleList &modules) { |
220 | 9.19k | SymbolContext empty_sc; |
221 | | |
222 | 9.19k | if (!m_target_sp) |
223 | 0 | return; |
224 | 9.19k | empty_sc.target_sp = m_target_sp; |
225 | | |
226 | 9.19k | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
227 | 138 | searcher.SearchCallback(*this, empty_sc, nullptr); |
228 | 138 | return; |
229 | 138 | } |
230 | | |
231 | 115k | for (ModuleSP module_sp : modules.Modules())9.06k { |
232 | 115k | if (!ModulePasses(module_sp)) |
233 | 0 | continue; |
234 | 115k | if (DoModuleIteration(module_sp, searcher) == Searcher::eCallbackReturnStop) |
235 | 0 | return; |
236 | 115k | } |
237 | 9.06k | } |
238 | | |
239 | | Searcher::CallbackReturn |
240 | | SearchFilter::DoModuleIteration(const lldb::ModuleSP &module_sp, |
241 | 115k | Searcher &searcher) { |
242 | 115k | SymbolContext matchingContext(m_target_sp, module_sp); |
243 | 115k | return DoModuleIteration(matchingContext, searcher); |
244 | 115k | } |
245 | | |
246 | | Searcher::CallbackReturn |
247 | | SearchFilter::DoModuleIteration(const SymbolContext &context, |
248 | 128k | Searcher &searcher) { |
249 | 128k | if (searcher.GetDepth() < lldb::eSearchDepthModule) |
250 | 0 | return Searcher::eCallbackReturnContinue; |
251 | | |
252 | 128k | if (context.module_sp) { |
253 | 127k | if (searcher.GetDepth() != lldb::eSearchDepthModule) |
254 | 52.6k | return DoCUIteration(context.module_sp, context, searcher); |
255 | | |
256 | 74.5k | SymbolContext matchingContext(context.module_sp.get()); |
257 | 74.5k | searcher.SearchCallback(*this, matchingContext, nullptr); |
258 | 74.5k | return Searcher::eCallbackReturnContinue; |
259 | 127k | } |
260 | | |
261 | 80.5k | for (ModuleSP module_sp : m_target_sp->GetImages().Modules())1.69k { |
262 | | // If this is the last level supplied, then call the callback directly, |
263 | | // otherwise descend. |
264 | 80.5k | if (!ModulePasses(module_sp)) |
265 | 1.58k | continue; |
266 | | |
267 | 78.9k | if (searcher.GetDepth() == lldb::eSearchDepthModule) { |
268 | 78.8k | SymbolContext matchingContext(m_target_sp, module_sp); |
269 | | |
270 | 78.8k | Searcher::CallbackReturn shouldContinue = |
271 | 78.8k | searcher.SearchCallback(*this, matchingContext, nullptr); |
272 | 78.8k | if (shouldContinue == Searcher::eCallbackReturnStop || |
273 | 78.8k | shouldContinue == Searcher::eCallbackReturnPop) |
274 | 0 | return shouldContinue; |
275 | 78.8k | } else { |
276 | 123 | Searcher::CallbackReturn shouldContinue = |
277 | 123 | DoCUIteration(module_sp, context, searcher); |
278 | 123 | if (shouldContinue == Searcher::eCallbackReturnStop) |
279 | 0 | return shouldContinue; |
280 | 123 | else if (shouldContinue == Searcher::eCallbackReturnPop) |
281 | 0 | continue; |
282 | 123 | } |
283 | 78.9k | } |
284 | | |
285 | 1.69k | return Searcher::eCallbackReturnContinue; |
286 | 1.69k | } |
287 | | |
288 | | Searcher::CallbackReturn |
289 | | SearchFilter::DoCUIteration(const ModuleSP &module_sp, |
290 | 53.7k | const SymbolContext &context, Searcher &searcher) { |
291 | 53.7k | Searcher::CallbackReturn shouldContinue; |
292 | 53.7k | if (context.comp_unit != nullptr) { |
293 | 1.03k | if (CompUnitPasses(*context.comp_unit)) { |
294 | 1.03k | SymbolContext matchingContext(m_target_sp, module_sp, context.comp_unit); |
295 | 1.03k | return searcher.SearchCallback(*this, matchingContext, nullptr); |
296 | 1.03k | } |
297 | 0 | return Searcher::eCallbackReturnContinue; |
298 | 1.03k | } |
299 | | |
300 | 52.7k | const size_t num_comp_units = module_sp->GetNumCompileUnits(); |
301 | 55.9k | for (size_t i = 0; i < num_comp_units; i++3.14k ) { |
302 | 3.14k | CompUnitSP cu_sp(module_sp->GetCompileUnitAtIndex(i)); |
303 | 3.14k | if (!cu_sp) |
304 | 0 | continue; |
305 | 3.14k | if (!CompUnitPasses(*(cu_sp.get()))) |
306 | 2.99k | continue; |
307 | | |
308 | 152 | if (searcher.GetDepth() == lldb::eSearchDepthCompUnit) { |
309 | 151 | SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get()); |
310 | | |
311 | 151 | shouldContinue = searcher.SearchCallback(*this, matchingContext, nullptr); |
312 | | |
313 | 151 | if (shouldContinue == Searcher::eCallbackReturnPop) |
314 | 0 | return Searcher::eCallbackReturnContinue; |
315 | 151 | else if (shouldContinue == Searcher::eCallbackReturnStop) |
316 | 0 | return shouldContinue; |
317 | 151 | continue; |
318 | 151 | } |
319 | | |
320 | | // First make sure this compile unit's functions are parsed |
321 | | // since CompUnit::ForeachFunction only iterates over already |
322 | | // parsed functions. |
323 | 1 | SymbolFile *sym_file = module_sp->GetSymbolFile(); |
324 | 1 | if (!sym_file) |
325 | 0 | continue; |
326 | 1 | if (!sym_file->ParseFunctions(*cu_sp)) |
327 | 0 | continue; |
328 | | // If we got any functions, use ForeachFunction to do the iteration. |
329 | 3 | cu_sp->ForeachFunction([&](const FunctionSP &func_sp) 1 { |
330 | 3 | if (!FunctionPasses(*func_sp.get())) |
331 | 0 | return false; // Didn't pass the filter, just keep going. |
332 | 3 | if (searcher.GetDepth() == lldb::eSearchDepthFunction) { |
333 | 3 | SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get(), |
334 | 3 | func_sp.get()); |
335 | 3 | shouldContinue = |
336 | 3 | searcher.SearchCallback(*this, matchingContext, nullptr); |
337 | 3 | } else { |
338 | 0 | shouldContinue = DoFunctionIteration(func_sp.get(), context, searcher); |
339 | 0 | } |
340 | 3 | return shouldContinue != Searcher::eCallbackReturnContinue; |
341 | 3 | }); |
342 | 1 | } |
343 | 52.7k | return Searcher::eCallbackReturnContinue; |
344 | 52.7k | } |
345 | | |
346 | | Searcher::CallbackReturn SearchFilter::DoFunctionIteration( |
347 | 0 | Function *function, const SymbolContext &context, Searcher &searcher) { |
348 | | // FIXME: Implement... |
349 | 0 | return Searcher::eCallbackReturnContinue; |
350 | 0 | } |
351 | | |
352 | | // SearchFilterForUnconstrainedSearches: |
353 | | // Selects a shared library matching a given file spec, consulting the targets |
354 | | // "black list". |
355 | | SearchFilterSP SearchFilterForUnconstrainedSearches::CreateFromStructuredData( |
356 | | const lldb::TargetSP& target_sp, |
357 | | const StructuredData::Dictionary &data_dict, |
358 | 13 | Status &error) { |
359 | | // No options for an unconstrained search. |
360 | 13 | return std::make_shared<SearchFilterForUnconstrainedSearches>(target_sp); |
361 | 13 | } |
362 | | |
363 | | StructuredData::ObjectSP |
364 | 27 | SearchFilterForUnconstrainedSearches::SerializeToStructuredData() { |
365 | | // The options dictionary is an empty dictionary: |
366 | 27 | auto result_sp = std::make_shared<StructuredData::Dictionary>(); |
367 | 27 | return WrapOptionsDict(result_sp); |
368 | 27 | } |
369 | | |
370 | | bool SearchFilterForUnconstrainedSearches::ModulePasses( |
371 | 0 | const FileSpec &module_spec) { |
372 | 0 | return !m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_spec); |
373 | 0 | } |
374 | | |
375 | | bool SearchFilterForUnconstrainedSearches::ModulePasses( |
376 | 273k | const lldb::ModuleSP &module_sp) { |
377 | 273k | if (!module_sp) |
378 | 0 | return true; |
379 | 273k | else if (m_target_sp->ModuleIsExcludedForUnconstrainedSearches(module_sp)) |
380 | 4.01k | return false; |
381 | 268k | return true; |
382 | 273k | } |
383 | | |
384 | 6 | SearchFilterSP SearchFilterForUnconstrainedSearches::DoCreateCopy() { |
385 | 6 | return std::make_shared<SearchFilterForUnconstrainedSearches>(*this); |
386 | 6 | } |
387 | | |
388 | | // SearchFilterByModule: |
389 | | // Selects a shared library matching a given file spec |
390 | | |
391 | | SearchFilterByModule::SearchFilterByModule(const lldb::TargetSP &target_sp, |
392 | | const FileSpec &module) |
393 | 904 | : SearchFilter(target_sp, FilterTy::ByModule), m_module_spec(module) {} |
394 | | |
395 | 904 | SearchFilterByModule::~SearchFilterByModule() = default; |
396 | | |
397 | 0 | bool SearchFilterByModule::ModulePasses(const ModuleSP &module_sp) { |
398 | 0 | return (module_sp && |
399 | 0 | FileSpec::Match(m_module_spec, module_sp->GetFileSpec())); |
400 | 0 | } |
401 | | |
402 | 0 | bool SearchFilterByModule::ModulePasses(const FileSpec &spec) { |
403 | 0 | return FileSpec::Match(m_module_spec, spec); |
404 | 0 | } |
405 | | |
406 | 0 | bool SearchFilterByModule::AddressPasses(Address &address) { |
407 | | // FIXME: Not yet implemented |
408 | 0 | return true; |
409 | 0 | } |
410 | | |
411 | 904 | void SearchFilterByModule::Search(Searcher &searcher) { |
412 | 904 | if (!m_target_sp) |
413 | 0 | return; |
414 | | |
415 | 904 | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
416 | 0 | SymbolContext empty_sc; |
417 | 0 | empty_sc.target_sp = m_target_sp; |
418 | 0 | searcher.SearchCallback(*this, empty_sc, nullptr); |
419 | 0 | } |
420 | | |
421 | | // If the module file spec is a full path, then we can just find the one |
422 | | // filespec that passes. Otherwise, we need to go through all modules and |
423 | | // find the ones that match the file name. |
424 | | |
425 | 904 | const ModuleList &target_modules = m_target_sp->GetImages(); |
426 | 904 | std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); |
427 | | |
428 | 40.9k | for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { |
429 | 40.9k | if (FileSpec::Match(m_module_spec, module_sp->GetFileSpec())) { |
430 | 936 | SymbolContext matchingContext(m_target_sp, module_sp); |
431 | 936 | Searcher::CallbackReturn shouldContinue; |
432 | | |
433 | 936 | shouldContinue = DoModuleIteration(matchingContext, searcher); |
434 | 936 | if (shouldContinue == Searcher::eCallbackReturnStop) |
435 | 0 | return; |
436 | 936 | } |
437 | 40.9k | } |
438 | 904 | } |
439 | | |
440 | 0 | void SearchFilterByModule::GetDescription(Stream *s) { |
441 | 0 | s->PutCString(", module = "); |
442 | 0 | s->PutCString(m_module_spec.GetFilename().AsCString("<Unknown>")); |
443 | 0 | } |
444 | | |
445 | 0 | uint32_t SearchFilterByModule::GetFilterRequiredItems() { |
446 | 0 | return eSymbolContextModule; |
447 | 0 | } |
448 | | |
449 | 0 | void SearchFilterByModule::Dump(Stream *s) const {} |
450 | | |
451 | 0 | SearchFilterSP SearchFilterByModule::DoCreateCopy() { |
452 | 0 | return std::make_shared<SearchFilterByModule>(*this); |
453 | 0 | } |
454 | | |
455 | | SearchFilterSP SearchFilterByModule::CreateFromStructuredData( |
456 | | const lldb::TargetSP& target_sp, |
457 | | const StructuredData::Dictionary &data_dict, |
458 | 0 | Status &error) { |
459 | 0 | StructuredData::Array *modules_array; |
460 | 0 | bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList), |
461 | 0 | modules_array); |
462 | 0 | if (!success) { |
463 | 0 | error.SetErrorString("SFBM::CFSD: Could not find the module list key."); |
464 | 0 | return nullptr; |
465 | 0 | } |
466 | | |
467 | 0 | size_t num_modules = modules_array->GetSize(); |
468 | 0 | if (num_modules > 1) { |
469 | 0 | error.SetErrorString( |
470 | 0 | "SFBM::CFSD: Only one modules allowed for SearchFilterByModule."); |
471 | 0 | return nullptr; |
472 | 0 | } |
473 | | |
474 | 0 | llvm::StringRef module; |
475 | 0 | success = modules_array->GetItemAtIndexAsString(0, module); |
476 | 0 | if (!success) { |
477 | 0 | error.SetErrorString("SFBM::CFSD: filter module item not a string."); |
478 | 0 | return nullptr; |
479 | 0 | } |
480 | 0 | FileSpec module_spec(module); |
481 | |
|
482 | 0 | return std::make_shared<SearchFilterByModule>(target_sp, module_spec); |
483 | 0 | } |
484 | | |
485 | 0 | StructuredData::ObjectSP SearchFilterByModule::SerializeToStructuredData() { |
486 | 0 | auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
487 | 0 | auto module_array_sp = std::make_shared<StructuredData::Array>(); |
488 | 0 | module_array_sp->AddItem( |
489 | 0 | std::make_shared<StructuredData::String>(m_module_spec.GetPath())); |
490 | 0 | options_dict_sp->AddItem(GetKey(OptionNames::ModList), module_array_sp); |
491 | 0 | return WrapOptionsDict(options_dict_sp); |
492 | 0 | } |
493 | | |
494 | | // SearchFilterByModuleList: |
495 | | // Selects a shared library matching a given file spec |
496 | | |
497 | | SearchFilterByModuleList::SearchFilterByModuleList( |
498 | | const lldb::TargetSP &target_sp, const FileSpecList &module_list) |
499 | 7.42k | : SearchFilter(target_sp, FilterTy::ByModules), |
500 | 7.42k | m_module_spec_list(module_list) {} |
501 | | |
502 | | SearchFilterByModuleList::SearchFilterByModuleList( |
503 | | const lldb::TargetSP &target_sp, const FileSpecList &module_list, |
504 | | enum FilterTy filter_ty) |
505 | 1.07k | : SearchFilter(target_sp, filter_ty), m_module_spec_list(module_list) {} |
506 | | |
507 | 8.44k | SearchFilterByModuleList::~SearchFilterByModuleList() = default; |
508 | | |
509 | 291k | bool SearchFilterByModuleList::ModulePasses(const ModuleSP &module_sp) { |
510 | 291k | if (m_module_spec_list.GetSize() == 0) |
511 | 157k | return true; |
512 | | |
513 | 134k | return module_sp && m_module_spec_list.FindFileIndex( |
514 | 134k | 0, module_sp->GetFileSpec(), false) != UINT32_MAX; |
515 | 291k | } |
516 | | |
517 | 0 | bool SearchFilterByModuleList::ModulePasses(const FileSpec &spec) { |
518 | 0 | if (m_module_spec_list.GetSize() == 0) |
519 | 0 | return true; |
520 | | |
521 | 0 | return m_module_spec_list.FindFileIndex(0, spec, true) != UINT32_MAX; |
522 | 0 | } |
523 | | |
524 | 9.12k | bool SearchFilterByModuleList::AddressPasses(Address &address) { |
525 | | // FIXME: Not yet implemented |
526 | 9.12k | return true; |
527 | 9.12k | } |
528 | | |
529 | 7.40k | void SearchFilterByModuleList::Search(Searcher &searcher) { |
530 | 7.40k | if (!m_target_sp) |
531 | 0 | return; |
532 | | |
533 | 7.40k | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
534 | 0 | SymbolContext empty_sc; |
535 | 0 | empty_sc.target_sp = m_target_sp; |
536 | 0 | searcher.SearchCallback(*this, empty_sc, nullptr); |
537 | 0 | } |
538 | | |
539 | | // If the module file spec is a full path, then we can just find the one |
540 | | // filespec that passes. Otherwise, we need to go through all modules and |
541 | | // find the ones that match the file name. |
542 | 206k | for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { |
543 | 206k | if (m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) == |
544 | 206k | UINT32_MAX) |
545 | 196k | continue; |
546 | 10.4k | SymbolContext matchingContext(m_target_sp, module_sp); |
547 | 10.4k | Searcher::CallbackReturn shouldContinue; |
548 | | |
549 | 10.4k | shouldContinue = DoModuleIteration(matchingContext, searcher); |
550 | 10.4k | if (shouldContinue == Searcher::eCallbackReturnStop) |
551 | 0 | return; |
552 | 10.4k | } |
553 | 7.40k | } |
554 | | |
555 | 54 | void SearchFilterByModuleList::GetDescription(Stream *s) { |
556 | 54 | size_t num_modules = m_module_spec_list.GetSize(); |
557 | 54 | if (num_modules == 1) { |
558 | 52 | s->Printf(", module = "); |
559 | 52 | s->PutCString( |
560 | 52 | m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString( |
561 | 52 | "<Unknown>")); |
562 | 52 | return; |
563 | 52 | } |
564 | | |
565 | 2 | s->Printf(", modules(%" PRIu64 ") = ", (uint64_t)num_modules); |
566 | 6 | for (size_t i = 0; i < num_modules; i++4 ) { |
567 | 4 | s->PutCString( |
568 | 4 | m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString( |
569 | 4 | "<Unknown>")); |
570 | 4 | if (i != num_modules - 1) |
571 | 2 | s->PutCString(", "); |
572 | 4 | } |
573 | 2 | } |
574 | | |
575 | 10.4k | uint32_t SearchFilterByModuleList::GetFilterRequiredItems() { |
576 | 10.4k | return eSymbolContextModule; |
577 | 10.4k | } |
578 | | |
579 | 0 | void SearchFilterByModuleList::Dump(Stream *s) const {} |
580 | | |
581 | 0 | lldb::SearchFilterSP SearchFilterByModuleList::DoCreateCopy() { |
582 | 0 | return std::make_shared<SearchFilterByModuleList>(*this); |
583 | 0 | } |
584 | | |
585 | | SearchFilterSP SearchFilterByModuleList::CreateFromStructuredData( |
586 | | const lldb::TargetSP& target_sp, |
587 | | const StructuredData::Dictionary &data_dict, |
588 | 1 | Status &error) { |
589 | 1 | StructuredData::Array *modules_array; |
590 | 1 | bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList), |
591 | 1 | modules_array); |
592 | | |
593 | 1 | if (!success) |
594 | 0 | return std::make_shared<SearchFilterByModuleList>(target_sp, |
595 | 0 | FileSpecList{}); |
596 | 1 | FileSpecList modules; |
597 | 1 | size_t num_modules = modules_array->GetSize(); |
598 | 3 | for (size_t i = 0; i < num_modules; i++2 ) { |
599 | 2 | llvm::StringRef module; |
600 | 2 | success = modules_array->GetItemAtIndexAsString(i, module); |
601 | 2 | if (!success) { |
602 | 0 | error.SetErrorStringWithFormat( |
603 | 0 | "SFBM::CFSD: filter module item %zu not a string.", i); |
604 | 0 | return nullptr; |
605 | 0 | } |
606 | 2 | modules.EmplaceBack(module); |
607 | 2 | } |
608 | 1 | return std::make_shared<SearchFilterByModuleList>(target_sp, modules); |
609 | 1 | } |
610 | | |
611 | | void SearchFilterByModuleList::SerializeUnwrapped( |
612 | 24 | StructuredData::DictionarySP &options_dict_sp) { |
613 | 24 | SerializeFileSpecList(options_dict_sp, OptionNames::ModList, |
614 | 24 | m_module_spec_list); |
615 | 24 | } |
616 | | |
617 | 15 | StructuredData::ObjectSP SearchFilterByModuleList::SerializeToStructuredData() { |
618 | 15 | auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
619 | 15 | SerializeUnwrapped(options_dict_sp); |
620 | 15 | return WrapOptionsDict(options_dict_sp); |
621 | 15 | } |
622 | | |
623 | | // SearchFilterByModuleListAndCU: |
624 | | // Selects a shared library matching a given file spec |
625 | | |
626 | | SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU( |
627 | | const lldb::TargetSP &target_sp, const FileSpecList &module_list, |
628 | | const FileSpecList &cu_list) |
629 | 1.07k | : SearchFilterByModuleList(target_sp, module_list, |
630 | 1.07k | FilterTy::ByModulesAndCU), |
631 | 1.07k | m_cu_spec_list(cu_list) {} |
632 | | |
633 | 1.07k | SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU() = default; |
634 | | |
635 | | lldb::SearchFilterSP SearchFilterByModuleListAndCU::CreateFromStructuredData( |
636 | | const lldb::TargetSP& target_sp, |
637 | | const StructuredData::Dictionary &data_dict, |
638 | 5 | Status &error) { |
639 | 5 | StructuredData::Array *modules_array = nullptr; |
640 | 5 | SearchFilterSP result_sp; |
641 | 5 | bool success = data_dict.GetValueForKeyAsArray(GetKey(OptionNames::ModList), |
642 | 5 | modules_array); |
643 | 5 | FileSpecList modules; |
644 | 5 | if (success) { |
645 | 2 | size_t num_modules = modules_array->GetSize(); |
646 | 6 | for (size_t i = 0; i < num_modules; i++4 ) { |
647 | 4 | llvm::StringRef module; |
648 | 4 | success = modules_array->GetItemAtIndexAsString(i, module); |
649 | 4 | if (!success) { |
650 | 0 | error.SetErrorStringWithFormat( |
651 | 0 | "SFBM::CFSD: filter module item %zu not a string.", i); |
652 | 0 | return result_sp; |
653 | 0 | } |
654 | 4 | modules.EmplaceBack(module); |
655 | 4 | } |
656 | 2 | } |
657 | | |
658 | 5 | StructuredData::Array *cus_array = nullptr; |
659 | 5 | success = |
660 | 5 | data_dict.GetValueForKeyAsArray(GetKey(OptionNames::CUList), cus_array); |
661 | 5 | if (!success) { |
662 | 0 | error.SetErrorString("SFBM::CFSD: Could not find the CU list key."); |
663 | 0 | return result_sp; |
664 | 0 | } |
665 | | |
666 | 5 | size_t num_cus = cus_array->GetSize(); |
667 | 5 | FileSpecList cus; |
668 | 14 | for (size_t i = 0; i < num_cus; i++9 ) { |
669 | 9 | llvm::StringRef cu; |
670 | 9 | success = cus_array->GetItemAtIndexAsString(i, cu); |
671 | 9 | if (!success) { |
672 | 0 | error.SetErrorStringWithFormat( |
673 | 0 | "SFBM::CFSD: filter CU item %zu not a string.", i); |
674 | 0 | return nullptr; |
675 | 0 | } |
676 | 9 | cus.EmplaceBack(cu); |
677 | 9 | } |
678 | | |
679 | 5 | return std::make_shared<SearchFilterByModuleListAndCU>( |
680 | 5 | target_sp, modules, cus); |
681 | 5 | } |
682 | | |
683 | | StructuredData::ObjectSP |
684 | 9 | SearchFilterByModuleListAndCU::SerializeToStructuredData() { |
685 | 9 | auto options_dict_sp = std::make_shared<StructuredData::Dictionary>(); |
686 | 9 | SearchFilterByModuleList::SerializeUnwrapped(options_dict_sp); |
687 | 9 | SerializeFileSpecList(options_dict_sp, OptionNames::CUList, m_cu_spec_list); |
688 | 9 | return WrapOptionsDict(options_dict_sp); |
689 | 9 | } |
690 | | |
691 | 1.29k | bool SearchFilterByModuleListAndCU::AddressPasses(Address &address) { |
692 | 1.29k | SymbolContext sym_ctx; |
693 | 1.29k | address.CalculateSymbolContext(&sym_ctx, eSymbolContextEverything); |
694 | 1.29k | if (!sym_ctx.comp_unit) { |
695 | 0 | if (m_cu_spec_list.GetSize() != 0) |
696 | 0 | return false; // Has no comp_unit so can't pass the file check. |
697 | 0 | } |
698 | 1.29k | FileSpec cu_spec; |
699 | 1.29k | if (sym_ctx.comp_unit) |
700 | 1.29k | cu_spec = sym_ctx.comp_unit->GetPrimaryFile(); |
701 | 1.29k | if (m_cu_spec_list.FindFileIndex(0, cu_spec, false) == UINT32_MAX) |
702 | 2 | return false; // Fails the file check |
703 | 1.28k | return SearchFilterByModuleList::ModulePasses(sym_ctx.module_sp); |
704 | 1.29k | } |
705 | | |
706 | 0 | bool SearchFilterByModuleListAndCU::CompUnitPasses(FileSpec &fileSpec) { |
707 | 0 | return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX; |
708 | 0 | } |
709 | | |
710 | 4.07k | bool SearchFilterByModuleListAndCU::CompUnitPasses(CompileUnit &compUnit) { |
711 | 4.07k | bool in_cu_list = m_cu_spec_list.FindFileIndex(0, compUnit.GetPrimaryFile(), |
712 | 4.07k | false) != UINT32_MAX; |
713 | 4.07k | if (!in_cu_list) |
714 | 2.99k | return false; |
715 | | |
716 | 1.08k | ModuleSP module_sp(compUnit.GetModule()); |
717 | 1.08k | if (!module_sp) |
718 | 0 | return true; |
719 | | |
720 | 1.08k | return SearchFilterByModuleList::ModulePasses(module_sp); |
721 | 1.08k | } |
722 | | |
723 | 1.08k | void SearchFilterByModuleListAndCU::Search(Searcher &searcher) { |
724 | 1.08k | if (!m_target_sp) |
725 | 0 | return; |
726 | | |
727 | 1.08k | if (searcher.GetDepth() == lldb::eSearchDepthTarget) { |
728 | 0 | SymbolContext empty_sc; |
729 | 0 | empty_sc.target_sp = m_target_sp; |
730 | 0 | searcher.SearchCallback(*this, empty_sc, nullptr); |
731 | 0 | } |
732 | | |
733 | | // If the module file spec is a full path, then we can just find the one |
734 | | // filespec that passes. Otherwise, we need to go through all modules and |
735 | | // find the ones that match the file name. |
736 | | |
737 | 1.08k | ModuleList matching_modules; |
738 | | |
739 | 1.08k | bool no_modules_in_filter = m_module_spec_list.GetSize() == 0; |
740 | 56.0k | for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { |
741 | 56.0k | if (!no_modules_in_filter && |
742 | 56.0k | m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) == |
743 | 1.05k | UINT32_MAX) |
744 | 1.03k | continue; |
745 | | |
746 | 55.0k | SymbolContext matchingContext(m_target_sp, module_sp); |
747 | 55.0k | Searcher::CallbackReturn shouldContinue; |
748 | | |
749 | 55.0k | if (searcher.GetDepth() == lldb::eSearchDepthModule) { |
750 | 269 | shouldContinue = DoModuleIteration(matchingContext, searcher); |
751 | 269 | if (shouldContinue == Searcher::eCallbackReturnStop) |
752 | 0 | return; |
753 | 269 | continue; |
754 | 269 | } |
755 | | |
756 | 54.7k | const size_t num_cu = module_sp->GetNumCompileUnits(); |
757 | 56.0k | for (size_t cu_idx = 0; cu_idx < num_cu; cu_idx++1.32k ) { |
758 | 1.32k | CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(cu_idx); |
759 | 1.32k | matchingContext.comp_unit = cu_sp.get(); |
760 | 1.32k | if (!matchingContext.comp_unit) |
761 | 0 | continue; |
762 | 1.32k | if (m_cu_spec_list.FindFileIndex( |
763 | 1.32k | 0, matchingContext.comp_unit->GetPrimaryFile(), false) == |
764 | 1.32k | UINT32_MAX) |
765 | 285 | continue; |
766 | 1.03k | shouldContinue = DoCUIteration(module_sp, matchingContext, searcher); |
767 | 1.03k | if (shouldContinue == Searcher::eCallbackReturnStop) |
768 | 0 | return; |
769 | 1.03k | } |
770 | 54.7k | } |
771 | 1.08k | } |
772 | | |
773 | 23 | void SearchFilterByModuleListAndCU::GetDescription(Stream *s) { |
774 | 23 | size_t num_modules = m_module_spec_list.GetSize(); |
775 | 23 | if (num_modules == 1) { |
776 | 0 | s->Printf(", module = "); |
777 | 0 | s->PutCString( |
778 | 0 | m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString( |
779 | 0 | "<Unknown>")); |
780 | 23 | } else if (num_modules > 0) { |
781 | 4 | s->Printf(", modules(%" PRIu64 ") = ", static_cast<uint64_t>(num_modules)); |
782 | 12 | for (size_t i = 0; i < num_modules; i++8 ) { |
783 | 8 | s->PutCString( |
784 | 8 | m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString( |
785 | 8 | "<Unknown>")); |
786 | 8 | if (i != num_modules - 1) |
787 | 4 | s->PutCString(", "); |
788 | 8 | } |
789 | 4 | } |
790 | 23 | } |
791 | | |
792 | 264 | uint32_t SearchFilterByModuleListAndCU::GetFilterRequiredItems() { |
793 | 264 | return eSymbolContextModule | eSymbolContextCompUnit; |
794 | 264 | } |
795 | | |
796 | 0 | void SearchFilterByModuleListAndCU::Dump(Stream *s) const {} |
797 | | |
798 | 7 | SearchFilterSP SearchFilterByModuleListAndCU::DoCreateCopy() { |
799 | 7 | return std::make_shared<SearchFilterByModuleListAndCU>(*this); |
800 | 7 | } |