1 | //===-- SymbolContext.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/Symbol/SymbolContext.h" |
10 | |
11 | #include "lldb/Core/Address.h" |
12 | #include "lldb/Core/Debugger.h" |
13 | #include "lldb/Core/Module.h" |
14 | #include "lldb/Core/ModuleSpec.h" |
15 | #include "lldb/Host/Host.h" |
16 | #include "lldb/Symbol/Block.h" |
17 | #include "lldb/Symbol/CompileUnit.h" |
18 | #include "lldb/Symbol/ObjectFile.h" |
19 | #include "lldb/Symbol/Symbol.h" |
20 | #include "lldb/Symbol/SymbolFile.h" |
21 | #include "lldb/Symbol/SymbolVendor.h" |
22 | #include "lldb/Symbol/Variable.h" |
23 | #include "lldb/Target/Language.h" |
24 | #include "lldb/Target/Target.h" |
25 | #include "lldb/Utility/LLDBLog.h" |
26 | #include "lldb/Utility/Log.h" |
27 | #include "lldb/Utility/Stream.h" |
28 | #include "lldb/Utility/StreamString.h" |
29 | #include "lldb/lldb-enumerations.h" |
30 | |
31 | using namespace lldb; |
32 | using namespace lldb_private; |
33 | |
34 | SymbolContext::SymbolContext() : target_sp(), module_sp(), line_entry() {} |
35 | |
36 | SymbolContext::SymbolContext(const ModuleSP &m, CompileUnit *cu, Function *f, |
37 | Block *b, LineEntry *le, Symbol *s) |
38 | : target_sp(), module_sp(m), comp_unit(cu), function(f), block(b), |
39 | line_entry(), symbol(s) { |
40 | if (le) |
41 | line_entry = *le; |
42 | } |
43 | |
44 | SymbolContext::SymbolContext(const TargetSP &t, const ModuleSP &m, |
45 | CompileUnit *cu, Function *f, Block *b, |
46 | LineEntry *le, Symbol *s) |
47 | : target_sp(t), module_sp(m), comp_unit(cu), function(f), block(b), |
48 | line_entry(), symbol(s) { |
49 | if (le) |
50 | line_entry = *le; |
51 | } |
52 | |
53 | SymbolContext::SymbolContext(SymbolContextScope *sc_scope) |
54 | : target_sp(), module_sp(), line_entry() { |
55 | sc_scope->CalculateSymbolContext(sc: this); |
56 | } |
57 | |
58 | SymbolContext::~SymbolContext() = default; |
59 | |
60 | void SymbolContext::Clear(bool clear_target) { |
61 | if (clear_target) |
62 | target_sp.reset(); |
63 | module_sp.reset(); |
64 | comp_unit = nullptr; |
65 | function = nullptr; |
66 | block = nullptr; |
67 | line_entry.Clear(); |
68 | symbol = nullptr; |
69 | variable = nullptr; |
70 | } |
71 | |
72 | bool SymbolContext::DumpStopContext( |
73 | Stream *s, ExecutionContextScope *exe_scope, const Address &addr, |
74 | bool show_fullpaths, bool show_module, bool show_inlined_frames, |
75 | bool show_function_arguments, bool show_function_name, |
76 | std::optional<Stream::HighlightSettings> settings) const { |
77 | bool dumped_something = false; |
78 | if (show_module && module_sp) { |
79 | if (show_fullpaths) |
80 | *s << module_sp->GetFileSpec(); |
81 | else |
82 | *s << module_sp->GetFileSpec().GetFilename(); |
83 | s->PutChar(ch: '`'); |
84 | dumped_something = true; |
85 | } |
86 | if (function != nullptr) { |
87 | SymbolContext inline_parent_sc; |
88 | Address inline_parent_addr; |
89 | if (!show_function_name) { |
90 | s->Printf(format: "<" ); |
91 | dumped_something = true; |
92 | } else { |
93 | ConstString name; |
94 | if (!show_function_arguments) |
95 | name = function->GetNameNoArguments(); |
96 | if (!name) |
97 | name = function->GetName(); |
98 | if (name) |
99 | s->PutCStringColorHighlighted(text: name.GetStringRef(), settings); |
100 | } |
101 | |
102 | if (addr.IsValid()) { |
103 | const addr_t function_offset = |
104 | addr.GetOffset() - |
105 | function->GetAddressRange().GetBaseAddress().GetOffset(); |
106 | if (!show_function_name) { |
107 | // Print +offset even if offset is 0 |
108 | dumped_something = true; |
109 | s->Printf(format: "+%" PRIu64 ">" , function_offset); |
110 | } else if (function_offset) { |
111 | dumped_something = true; |
112 | s->Printf(format: " + %" PRIu64, function_offset); |
113 | } |
114 | } |
115 | |
116 | if (GetParentOfInlinedScope(curr_frame_pc: addr, next_frame_sc&: inline_parent_sc, inlined_frame_addr&: inline_parent_addr)) { |
117 | dumped_something = true; |
118 | Block *inlined_block = block->GetContainingInlinedBlock(); |
119 | const InlineFunctionInfo *inlined_block_info = |
120 | inlined_block->GetInlinedFunctionInfo(); |
121 | s->Printf(format: " [inlined] %s" , inlined_block_info->GetName().GetCString()); |
122 | |
123 | lldb_private::AddressRange block_range; |
124 | if (inlined_block->GetRangeContainingAddress(addr, range&: block_range)) { |
125 | const addr_t inlined_function_offset = |
126 | addr.GetOffset() - block_range.GetBaseAddress().GetOffset(); |
127 | if (inlined_function_offset) { |
128 | s->Printf(format: " + %" PRIu64, inlined_function_offset); |
129 | } |
130 | } |
131 | // "line_entry" will always be valid as GetParentOfInlinedScope(...) will |
132 | // fill it in correctly with the calling file and line. Previous code |
133 | // was extracting the calling file and line from inlined_block_info and |
134 | // using it right away which is not correct. On the first call to this |
135 | // function "line_entry" will contain the actual line table entry. On |
136 | // susequent calls "line_entry" will contain the calling file and line |
137 | // from the previous inline info. |
138 | if (line_entry.IsValid()) { |
139 | s->PutCString(cstr: " at " ); |
140 | line_entry.DumpStopContext(s, show_fullpaths); |
141 | } |
142 | |
143 | if (show_inlined_frames) { |
144 | s->EOL(); |
145 | s->Indent(); |
146 | const bool show_function_name = true; |
147 | return inline_parent_sc.DumpStopContext( |
148 | s, exe_scope, addr: inline_parent_addr, show_fullpaths, show_module, |
149 | show_inlined_frames, show_function_arguments, show_function_name); |
150 | } |
151 | } else { |
152 | if (line_entry.IsValid()) { |
153 | dumped_something = true; |
154 | s->PutCString(cstr: " at " ); |
155 | if (line_entry.DumpStopContext(s, show_fullpaths)) |
156 | dumped_something = true; |
157 | } |
158 | } |
159 | } else if (symbol != nullptr) { |
160 | if (!show_function_name) { |
161 | s->Printf(format: "<" ); |
162 | dumped_something = true; |
163 | } else if (symbol->GetName()) { |
164 | dumped_something = true; |
165 | if (symbol->GetType() == eSymbolTypeTrampoline) |
166 | s->PutCString(cstr: "symbol stub for: " ); |
167 | s->PutCStringColorHighlighted(text: symbol->GetName().GetStringRef(), settings); |
168 | } |
169 | |
170 | if (addr.IsValid() && symbol->ValueIsAddress()) { |
171 | const addr_t symbol_offset = |
172 | addr.GetOffset() - symbol->GetAddressRef().GetOffset(); |
173 | if (!show_function_name) { |
174 | // Print +offset even if offset is 0 |
175 | dumped_something = true; |
176 | s->Printf(format: "+%" PRIu64 ">" , symbol_offset); |
177 | } else if (symbol_offset) { |
178 | dumped_something = true; |
179 | s->Printf(format: " + %" PRIu64, symbol_offset); |
180 | } |
181 | } |
182 | } else if (addr.IsValid()) { |
183 | addr.Dump(s, exe_scope, style: Address::DumpStyleModuleWithFileAddress); |
184 | dumped_something = true; |
185 | } |
186 | return dumped_something; |
187 | } |
188 | |
189 | void SymbolContext::GetDescription( |
190 | Stream *s, lldb::DescriptionLevel level, Target *target, |
191 | std::optional<Stream::HighlightSettings> settings) const { |
192 | if (module_sp) { |
193 | s->Indent(s: " Module: file = \"" ); |
194 | module_sp->GetFileSpec().Dump(s&: s->AsRawOstream()); |
195 | *s << '"'; |
196 | if (module_sp->GetArchitecture().IsValid()) |
197 | s->Printf(format: ", arch = \"%s\"" , |
198 | module_sp->GetArchitecture().GetArchitectureName()); |
199 | s->EOL(); |
200 | } |
201 | |
202 | if (comp_unit != nullptr) { |
203 | s->Indent(s: "CompileUnit: " ); |
204 | comp_unit->GetDescription(s, level); |
205 | s->EOL(); |
206 | } |
207 | |
208 | if (function != nullptr) { |
209 | s->Indent(s: " Function: " ); |
210 | function->GetDescription(s, level, target); |
211 | s->EOL(); |
212 | |
213 | Type *func_type = function->GetType(); |
214 | if (func_type) { |
215 | s->Indent(s: " FuncType: " ); |
216 | func_type->GetDescription(s, level, show_name: false, exe_scope: target); |
217 | s->EOL(); |
218 | } |
219 | } |
220 | |
221 | if (block != nullptr) { |
222 | std::vector<Block *> blocks; |
223 | blocks.push_back(x: block); |
224 | Block *parent_block = block->GetParent(); |
225 | |
226 | while (parent_block) { |
227 | blocks.push_back(x: parent_block); |
228 | parent_block = parent_block->GetParent(); |
229 | } |
230 | std::vector<Block *>::reverse_iterator pos; |
231 | std::vector<Block *>::reverse_iterator begin = blocks.rbegin(); |
232 | std::vector<Block *>::reverse_iterator end = blocks.rend(); |
233 | for (pos = begin; pos != end; ++pos) { |
234 | if (pos == begin) |
235 | s->Indent(s: " Blocks: " ); |
236 | else |
237 | s->Indent(s: " " ); |
238 | (*pos)->GetDescription(s, function, level, target); |
239 | s->EOL(); |
240 | } |
241 | } |
242 | |
243 | if (line_entry.IsValid()) { |
244 | s->Indent(s: " LineEntry: " ); |
245 | line_entry.GetDescription(s, level, cu: comp_unit, target, show_address_only: false); |
246 | s->EOL(); |
247 | } |
248 | |
249 | if (symbol != nullptr) { |
250 | s->Indent(s: " Symbol: " ); |
251 | symbol->GetDescription(s, level, target, settings); |
252 | s->EOL(); |
253 | } |
254 | |
255 | if (variable != nullptr) { |
256 | s->Indent(s: " Variable: " ); |
257 | |
258 | s->Printf(format: "id = {0x%8.8" PRIx64 "}, " , variable->GetID()); |
259 | |
260 | switch (variable->GetScope()) { |
261 | case eValueTypeVariableGlobal: |
262 | s->PutCString(cstr: "kind = global, " ); |
263 | break; |
264 | |
265 | case eValueTypeVariableStatic: |
266 | s->PutCString(cstr: "kind = static, " ); |
267 | break; |
268 | |
269 | case eValueTypeVariableArgument: |
270 | s->PutCString(cstr: "kind = argument, " ); |
271 | break; |
272 | |
273 | case eValueTypeVariableLocal: |
274 | s->PutCString(cstr: "kind = local, " ); |
275 | break; |
276 | |
277 | case eValueTypeVariableThreadLocal: |
278 | s->PutCString(cstr: "kind = thread local, " ); |
279 | break; |
280 | |
281 | default: |
282 | break; |
283 | } |
284 | |
285 | s->Printf(format: "name = \"%s\"\n" , variable->GetName().GetCString()); |
286 | } |
287 | } |
288 | |
289 | uint32_t SymbolContext::GetResolvedMask() const { |
290 | uint32_t resolved_mask = 0; |
291 | if (target_sp) |
292 | resolved_mask |= eSymbolContextTarget; |
293 | if (module_sp) |
294 | resolved_mask |= eSymbolContextModule; |
295 | if (comp_unit) |
296 | resolved_mask |= eSymbolContextCompUnit; |
297 | if (function) |
298 | resolved_mask |= eSymbolContextFunction; |
299 | if (block) |
300 | resolved_mask |= eSymbolContextBlock; |
301 | if (line_entry.IsValid()) |
302 | resolved_mask |= eSymbolContextLineEntry; |
303 | if (symbol) |
304 | resolved_mask |= eSymbolContextSymbol; |
305 | if (variable) |
306 | resolved_mask |= eSymbolContextVariable; |
307 | return resolved_mask; |
308 | } |
309 | |
310 | void SymbolContext::Dump(Stream *s, Target *target) const { |
311 | *s << this << ": " ; |
312 | s->Indent(); |
313 | s->PutCString(cstr: "SymbolContext" ); |
314 | s->IndentMore(); |
315 | s->EOL(); |
316 | s->IndentMore(); |
317 | s->Indent(); |
318 | *s << "Module = " << module_sp.get() << ' '; |
319 | if (module_sp) |
320 | module_sp->GetFileSpec().Dump(s&: s->AsRawOstream()); |
321 | s->EOL(); |
322 | s->Indent(); |
323 | *s << "CompileUnit = " << comp_unit; |
324 | if (comp_unit != nullptr) |
325 | s->Format(format: " {{{0:x-16}} {1}" , args: comp_unit->GetID(), |
326 | args: comp_unit->GetPrimaryFile()); |
327 | s->EOL(); |
328 | s->Indent(); |
329 | *s << "Function = " << function; |
330 | if (function != nullptr) { |
331 | s->Format(format: " {{{0:x-16}} {1}, address-range = " , args: function->GetID(), |
332 | args: function->GetType()->GetName()); |
333 | function->GetAddressRange().Dump(s, target, style: Address::DumpStyleLoadAddress, |
334 | fallback_style: Address::DumpStyleModuleWithFileAddress); |
335 | s->EOL(); |
336 | s->Indent(); |
337 | Type *func_type = function->GetType(); |
338 | if (func_type) { |
339 | *s << " Type = " ; |
340 | func_type->Dump(s, show_context: false); |
341 | } |
342 | } |
343 | s->EOL(); |
344 | s->Indent(); |
345 | *s << "Block = " << block; |
346 | if (block != nullptr) |
347 | s->Format(format: " {{{0:x-16}}" , args: block->GetID()); |
348 | s->EOL(); |
349 | s->Indent(); |
350 | *s << "LineEntry = " ; |
351 | line_entry.Dump(s, target, show_file: true, style: Address::DumpStyleLoadAddress, |
352 | fallback_style: Address::DumpStyleModuleWithFileAddress, show_range: true); |
353 | s->EOL(); |
354 | s->Indent(); |
355 | *s << "Symbol = " << symbol; |
356 | if (symbol != nullptr && symbol->GetMangled()) |
357 | *s << ' ' << symbol->GetName().AsCString(); |
358 | s->EOL(); |
359 | *s << "Variable = " << variable; |
360 | if (variable != nullptr) { |
361 | s->Format(format: " {{{0:x-16}} {1}" , args: variable->GetID(), |
362 | args: variable->GetType()->GetName()); |
363 | s->EOL(); |
364 | } |
365 | s->IndentLess(); |
366 | s->IndentLess(); |
367 | } |
368 | |
369 | bool lldb_private::operator==(const SymbolContext &lhs, |
370 | const SymbolContext &rhs) { |
371 | return lhs.function == rhs.function && lhs.symbol == rhs.symbol && |
372 | lhs.module_sp.get() == rhs.module_sp.get() && |
373 | lhs.comp_unit == rhs.comp_unit && |
374 | lhs.target_sp.get() == rhs.target_sp.get() && |
375 | LineEntry::Compare(lhs: lhs.line_entry, rhs: rhs.line_entry) == 0 && |
376 | lhs.variable == rhs.variable; |
377 | } |
378 | |
379 | bool lldb_private::operator!=(const SymbolContext &lhs, |
380 | const SymbolContext &rhs) { |
381 | return !(lhs == rhs); |
382 | } |
383 | |
384 | bool SymbolContext::GetAddressRange(uint32_t scope, uint32_t range_idx, |
385 | bool use_inline_block_range, |
386 | AddressRange &range) const { |
387 | if ((scope & eSymbolContextLineEntry) && line_entry.IsValid()) { |
388 | range = line_entry.range; |
389 | return true; |
390 | } |
391 | |
392 | if ((scope & eSymbolContextBlock) && (block != nullptr)) { |
393 | if (use_inline_block_range) { |
394 | Block *inline_block = block->GetContainingInlinedBlock(); |
395 | if (inline_block) |
396 | return inline_block->GetRangeAtIndex(range_idx, range); |
397 | } else { |
398 | return block->GetRangeAtIndex(range_idx, range); |
399 | } |
400 | } |
401 | |
402 | if ((scope & eSymbolContextFunction) && (function != nullptr)) { |
403 | if (range_idx == 0) { |
404 | range = function->GetAddressRange(); |
405 | return true; |
406 | } |
407 | } |
408 | |
409 | if ((scope & eSymbolContextSymbol) && (symbol != nullptr)) { |
410 | if (range_idx == 0) { |
411 | if (symbol->ValueIsAddress()) { |
412 | range.GetBaseAddress() = symbol->GetAddressRef(); |
413 | range.SetByteSize(symbol->GetByteSize()); |
414 | return true; |
415 | } |
416 | } |
417 | } |
418 | range.Clear(); |
419 | return false; |
420 | } |
421 | |
422 | LanguageType SymbolContext::GetLanguage() const { |
423 | LanguageType lang; |
424 | if (function && (lang = function->GetLanguage()) != eLanguageTypeUnknown) { |
425 | return lang; |
426 | } else if (variable && |
427 | (lang = variable->GetLanguage()) != eLanguageTypeUnknown) { |
428 | return lang; |
429 | } else if (symbol && (lang = symbol->GetLanguage()) != eLanguageTypeUnknown) { |
430 | return lang; |
431 | } else if (comp_unit && |
432 | (lang = comp_unit->GetLanguage()) != eLanguageTypeUnknown) { |
433 | return lang; |
434 | } else if (symbol) { |
435 | // If all else fails, try to guess the language from the name. |
436 | return symbol->GetMangled().GuessLanguage(); |
437 | } |
438 | return eLanguageTypeUnknown; |
439 | } |
440 | |
441 | bool SymbolContext::GetParentOfInlinedScope(const Address &curr_frame_pc, |
442 | SymbolContext &next_frame_sc, |
443 | Address &next_frame_pc) const { |
444 | next_frame_sc.Clear(clear_target: false); |
445 | next_frame_pc.Clear(); |
446 | |
447 | if (block) { |
448 | // const addr_t curr_frame_file_addr = curr_frame_pc.GetFileAddress(); |
449 | |
450 | // In order to get the parent of an inlined function we first need to see |
451 | // if we are in an inlined block as "this->block" could be an inlined |
452 | // block, or a parent of "block" could be. So lets check if this block or |
453 | // one of this blocks parents is an inlined function. |
454 | Block *curr_inlined_block = block->GetContainingInlinedBlock(); |
455 | if (curr_inlined_block) { |
456 | // "this->block" is contained in an inline function block, so to get the |
457 | // scope above the inlined block, we get the parent of the inlined block |
458 | // itself |
459 | Block *next_frame_block = curr_inlined_block->GetParent(); |
460 | // Now calculate the symbol context of the containing block |
461 | next_frame_block->CalculateSymbolContext(sc: &next_frame_sc); |
462 | |
463 | // If we get here we weren't able to find the return line entry using the |
464 | // nesting of the blocks and the line table. So just use the call site |
465 | // info from our inlined block. |
466 | |
467 | AddressRange range; |
468 | if (curr_inlined_block->GetRangeContainingAddress(addr: curr_frame_pc, range)) { |
469 | // To see there this new frame block it, we need to look at the call |
470 | // site information from |
471 | const InlineFunctionInfo *curr_inlined_block_inlined_info = |
472 | curr_inlined_block->GetInlinedFunctionInfo(); |
473 | next_frame_pc = range.GetBaseAddress(); |
474 | next_frame_sc.line_entry.range.GetBaseAddress() = next_frame_pc; |
475 | next_frame_sc.line_entry.file_sp = std::make_shared<SupportFile>( |
476 | args: curr_inlined_block_inlined_info->GetCallSite().GetFile()); |
477 | next_frame_sc.line_entry.original_file_sp = |
478 | std::make_shared<SupportFile>( |
479 | args: curr_inlined_block_inlined_info->GetCallSite().GetFile()); |
480 | next_frame_sc.line_entry.line = |
481 | curr_inlined_block_inlined_info->GetCallSite().GetLine(); |
482 | next_frame_sc.line_entry.column = |
483 | curr_inlined_block_inlined_info->GetCallSite().GetColumn(); |
484 | return true; |
485 | } else { |
486 | Log *log = GetLog(mask: LLDBLog::Symbols); |
487 | |
488 | if (log) { |
489 | LLDB_LOGF( |
490 | log, |
491 | "warning: inlined block 0x%8.8" PRIx64 |
492 | " doesn't have a range that contains file address 0x%" PRIx64, |
493 | curr_inlined_block->GetID(), curr_frame_pc.GetFileAddress()); |
494 | } |
495 | #ifdef LLDB_CONFIGURATION_DEBUG |
496 | else { |
497 | ObjectFile *objfile = nullptr; |
498 | if (module_sp) { |
499 | if (SymbolFile *symbol_file = module_sp->GetSymbolFile()) |
500 | objfile = symbol_file->GetObjectFile(); |
501 | } |
502 | if (objfile) { |
503 | Debugger::ReportWarning(message: llvm::formatv( |
504 | Fmt: "inlined block {0:x} doesn't have a range that contains file " |
505 | "address {1:x} in {2}" , |
506 | Vals: curr_inlined_block->GetID(), Vals: curr_frame_pc.GetFileAddress(), |
507 | Vals: objfile->GetFileSpec().GetPath())); |
508 | } else { |
509 | Debugger::ReportWarning(message: llvm::formatv( |
510 | Fmt: "inlined block {0:x} doesn't have a range that contains file " |
511 | "address {1:x}" , |
512 | Vals: curr_inlined_block->GetID(), Vals: curr_frame_pc.GetFileAddress())); |
513 | } |
514 | } |
515 | #endif |
516 | } |
517 | } |
518 | } |
519 | |
520 | return false; |
521 | } |
522 | |
523 | Block *SymbolContext::GetFunctionBlock() { |
524 | if (function) { |
525 | if (block) { |
526 | // If this symbol context has a block, check to see if this block is |
527 | // itself, or is contained within a block with inlined function |
528 | // information. If so, then the inlined block is the block that defines |
529 | // the function. |
530 | Block *inlined_block = block->GetContainingInlinedBlock(); |
531 | if (inlined_block) |
532 | return inlined_block; |
533 | |
534 | // The block in this symbol context is not inside an inlined block, so |
535 | // the block that defines the function is the function's top level block, |
536 | // which is returned below. |
537 | } |
538 | |
539 | // There is no block information in this symbol context, so we must assume |
540 | // that the block that is desired is the top level block of the function |
541 | // itself. |
542 | return &function->GetBlock(can_create: true); |
543 | } |
544 | return nullptr; |
545 | } |
546 | |
547 | llvm::StringRef SymbolContext::GetInstanceVariableName() { |
548 | LanguageType lang_type = eLanguageTypeUnknown; |
549 | |
550 | if (Block *function_block = GetFunctionBlock()) |
551 | if (CompilerDeclContext decl_ctx = function_block->GetDeclContext()) |
552 | lang_type = decl_ctx.GetLanguage(); |
553 | |
554 | if (lang_type == eLanguageTypeUnknown) |
555 | lang_type = GetLanguage(); |
556 | |
557 | if (auto *lang = Language::FindPlugin(language: lang_type)) |
558 | return lang->GetInstanceVariableName(); |
559 | |
560 | return {}; |
561 | } |
562 | |
563 | void SymbolContext::SortTypeList(TypeMap &type_map, TypeList &type_list) const { |
564 | Block *curr_block = block; |
565 | bool isInlinedblock = false; |
566 | if (curr_block != nullptr && |
567 | curr_block->GetContainingInlinedBlock() != nullptr) |
568 | isInlinedblock = true; |
569 | |
570 | // Find all types that match the current block if we have one and put them |
571 | // first in the list. Keep iterating up through all blocks. |
572 | while (curr_block != nullptr && !isInlinedblock) { |
573 | type_map.ForEach( |
574 | callback: [curr_block, &type_list](const lldb::TypeSP &type_sp) -> bool { |
575 | SymbolContextScope *scs = type_sp->GetSymbolContextScope(); |
576 | if (scs && curr_block == scs->CalculateSymbolContextBlock()) |
577 | type_list.Insert(type: type_sp); |
578 | return true; // Keep iterating |
579 | }); |
580 | |
581 | // Remove any entries that are now in "type_list" from "type_map" since we |
582 | // can't remove from type_map while iterating |
583 | type_list.ForEach(callback: [&type_map](const lldb::TypeSP &type_sp) -> bool { |
584 | type_map.Remove(type_sp); |
585 | return true; // Keep iterating |
586 | }); |
587 | curr_block = curr_block->GetParent(); |
588 | } |
589 | // Find all types that match the current function, if we have onem, and put |
590 | // them next in the list. |
591 | if (function != nullptr && !type_map.Empty()) { |
592 | const size_t old_type_list_size = type_list.GetSize(); |
593 | type_map.ForEach(callback: [this, &type_list](const lldb::TypeSP &type_sp) -> bool { |
594 | SymbolContextScope *scs = type_sp->GetSymbolContextScope(); |
595 | if (scs && function == scs->CalculateSymbolContextFunction()) |
596 | type_list.Insert(type: type_sp); |
597 | return true; // Keep iterating |
598 | }); |
599 | |
600 | // Remove any entries that are now in "type_list" from "type_map" since we |
601 | // can't remove from type_map while iterating |
602 | const size_t new_type_list_size = type_list.GetSize(); |
603 | if (new_type_list_size > old_type_list_size) { |
604 | for (size_t i = old_type_list_size; i < new_type_list_size; ++i) |
605 | type_map.Remove(type_sp: type_list.GetTypeAtIndex(idx: i)); |
606 | } |
607 | } |
608 | // Find all types that match the current compile unit, if we have one, and |
609 | // put them next in the list. |
610 | if (comp_unit != nullptr && !type_map.Empty()) { |
611 | const size_t old_type_list_size = type_list.GetSize(); |
612 | |
613 | type_map.ForEach(callback: [this, &type_list](const lldb::TypeSP &type_sp) -> bool { |
614 | SymbolContextScope *scs = type_sp->GetSymbolContextScope(); |
615 | if (scs && comp_unit == scs->CalculateSymbolContextCompileUnit()) |
616 | type_list.Insert(type: type_sp); |
617 | return true; // Keep iterating |
618 | }); |
619 | |
620 | // Remove any entries that are now in "type_list" from "type_map" since we |
621 | // can't remove from type_map while iterating |
622 | const size_t new_type_list_size = type_list.GetSize(); |
623 | if (new_type_list_size > old_type_list_size) { |
624 | for (size_t i = old_type_list_size; i < new_type_list_size; ++i) |
625 | type_map.Remove(type_sp: type_list.GetTypeAtIndex(idx: i)); |
626 | } |
627 | } |
628 | // Find all types that match the current module, if we have one, and put them |
629 | // next in the list. |
630 | if (module_sp && !type_map.Empty()) { |
631 | const size_t old_type_list_size = type_list.GetSize(); |
632 | type_map.ForEach(callback: [this, &type_list](const lldb::TypeSP &type_sp) -> bool { |
633 | SymbolContextScope *scs = type_sp->GetSymbolContextScope(); |
634 | if (scs && module_sp == scs->CalculateSymbolContextModule()) |
635 | type_list.Insert(type: type_sp); |
636 | return true; // Keep iterating |
637 | }); |
638 | // Remove any entries that are now in "type_list" from "type_map" since we |
639 | // can't remove from type_map while iterating |
640 | const size_t new_type_list_size = type_list.GetSize(); |
641 | if (new_type_list_size > old_type_list_size) { |
642 | for (size_t i = old_type_list_size; i < new_type_list_size; ++i) |
643 | type_map.Remove(type_sp: type_list.GetTypeAtIndex(idx: i)); |
644 | } |
645 | } |
646 | // Any types that are left get copied into the list an any order. |
647 | if (!type_map.Empty()) { |
648 | type_map.ForEach(callback: [&type_list](const lldb::TypeSP &type_sp) -> bool { |
649 | type_list.Insert(type: type_sp); |
650 | return true; // Keep iterating |
651 | }); |
652 | } |
653 | } |
654 | |
655 | ConstString |
656 | SymbolContext::GetFunctionName(Mangled::NamePreference preference) const { |
657 | if (function) { |
658 | if (block) { |
659 | Block *inlined_block = block->GetContainingInlinedBlock(); |
660 | |
661 | if (inlined_block) { |
662 | const InlineFunctionInfo *inline_info = |
663 | inlined_block->GetInlinedFunctionInfo(); |
664 | if (inline_info) |
665 | return inline_info->GetName(); |
666 | } |
667 | } |
668 | return function->GetMangled().GetName(preference); |
669 | } else if (symbol && symbol->ValueIsAddress()) { |
670 | return symbol->GetMangled().GetName(preference); |
671 | } else { |
672 | // No function, return an empty string. |
673 | return ConstString(); |
674 | } |
675 | } |
676 | |
677 | LineEntry SymbolContext::GetFunctionStartLineEntry() const { |
678 | LineEntry line_entry; |
679 | Address start_addr; |
680 | if (block) { |
681 | Block *inlined_block = block->GetContainingInlinedBlock(); |
682 | if (inlined_block) { |
683 | if (inlined_block->GetStartAddress(addr&: start_addr)) { |
684 | if (start_addr.CalculateSymbolContextLineEntry(line_entry)) |
685 | return line_entry; |
686 | } |
687 | return LineEntry(); |
688 | } |
689 | } |
690 | |
691 | if (function) { |
692 | if (function->GetAddressRange() |
693 | .GetBaseAddress() |
694 | .CalculateSymbolContextLineEntry(line_entry)) |
695 | return line_entry; |
696 | } |
697 | return LineEntry(); |
698 | } |
699 | |
700 | bool SymbolContext::GetAddressRangeFromHereToEndLine(uint32_t end_line, |
701 | AddressRange &range, |
702 | Status &error) { |
703 | if (!line_entry.IsValid()) { |
704 | error.SetErrorString("Symbol context has no line table." ); |
705 | return false; |
706 | } |
707 | |
708 | range = line_entry.range; |
709 | if (line_entry.line > end_line) { |
710 | error.SetErrorStringWithFormat( |
711 | "end line option %d must be after the current line: %d" , end_line, |
712 | line_entry.line); |
713 | return false; |
714 | } |
715 | |
716 | uint32_t line_index = 0; |
717 | bool found = false; |
718 | while (true) { |
719 | LineEntry this_line; |
720 | line_index = comp_unit->FindLineEntry(start_idx: line_index, line: line_entry.line, file_spec_ptr: nullptr, |
721 | exact: false, line_entry: &this_line); |
722 | if (line_index == UINT32_MAX) |
723 | break; |
724 | if (LineEntry::Compare(lhs: this_line, rhs: line_entry) == 0) { |
725 | found = true; |
726 | break; |
727 | } |
728 | } |
729 | |
730 | LineEntry end_entry; |
731 | if (!found) { |
732 | // Can't find the index of the SymbolContext's line entry in the |
733 | // SymbolContext's CompUnit. |
734 | error.SetErrorString( |
735 | "Can't find the current line entry in the CompUnit - can't process " |
736 | "the end-line option" ); |
737 | return false; |
738 | } |
739 | |
740 | line_index = comp_unit->FindLineEntry(start_idx: line_index, line: end_line, file_spec_ptr: nullptr, exact: false, |
741 | line_entry: &end_entry); |
742 | if (line_index == UINT32_MAX) { |
743 | error.SetErrorStringWithFormat( |
744 | "could not find a line table entry corresponding " |
745 | "to end line number %d" , |
746 | end_line); |
747 | return false; |
748 | } |
749 | |
750 | Block *func_block = GetFunctionBlock(); |
751 | if (func_block && func_block->GetRangeIndexContainingAddress( |
752 | addr: end_entry.range.GetBaseAddress()) == UINT32_MAX) { |
753 | error.SetErrorStringWithFormat( |
754 | "end line number %d is not contained within the current function." , |
755 | end_line); |
756 | return false; |
757 | } |
758 | |
759 | lldb::addr_t range_size = end_entry.range.GetBaseAddress().GetFileAddress() - |
760 | range.GetBaseAddress().GetFileAddress(); |
761 | range.SetByteSize(range_size); |
762 | return true; |
763 | } |
764 | |
765 | const Symbol *SymbolContext::FindBestGlobalDataSymbol(ConstString name, |
766 | Status &error) { |
767 | error.Clear(); |
768 | |
769 | if (!target_sp) { |
770 | return nullptr; |
771 | } |
772 | |
773 | Target &target = *target_sp; |
774 | Module *module = module_sp.get(); |
775 | |
776 | auto ProcessMatches = [this, &name, &target, |
777 | module](const SymbolContextList &sc_list, |
778 | Status &error) -> const Symbol * { |
779 | llvm::SmallVector<const Symbol *, 1> external_symbols; |
780 | llvm::SmallVector<const Symbol *, 1> internal_symbols; |
781 | for (const SymbolContext &sym_ctx : sc_list) { |
782 | if (sym_ctx.symbol) { |
783 | const Symbol *symbol = sym_ctx.symbol; |
784 | const Address sym_address = symbol->GetAddress(); |
785 | |
786 | if (sym_address.IsValid()) { |
787 | switch (symbol->GetType()) { |
788 | case eSymbolTypeData: |
789 | case eSymbolTypeRuntime: |
790 | case eSymbolTypeAbsolute: |
791 | case eSymbolTypeObjCClass: |
792 | case eSymbolTypeObjCMetaClass: |
793 | case eSymbolTypeObjCIVar: |
794 | if (symbol->GetDemangledNameIsSynthesized()) { |
795 | // If the demangled name was synthesized, then don't use it for |
796 | // expressions. Only let the symbol match if the mangled named |
797 | // matches for these symbols. |
798 | if (symbol->GetMangled().GetMangledName() != name) |
799 | break; |
800 | } |
801 | if (symbol->IsExternal()) { |
802 | external_symbols.push_back(Elt: symbol); |
803 | } else { |
804 | internal_symbols.push_back(Elt: symbol); |
805 | } |
806 | break; |
807 | case eSymbolTypeReExported: { |
808 | ConstString reexport_name = symbol->GetReExportedSymbolName(); |
809 | if (reexport_name) { |
810 | ModuleSP reexport_module_sp; |
811 | ModuleSpec reexport_module_spec; |
812 | reexport_module_spec.GetPlatformFileSpec() = |
813 | symbol->GetReExportedSymbolSharedLibrary(); |
814 | if (reexport_module_spec.GetPlatformFileSpec()) { |
815 | reexport_module_sp = |
816 | target.GetImages().FindFirstModule(module_spec: reexport_module_spec); |
817 | if (!reexport_module_sp) { |
818 | reexport_module_spec.GetPlatformFileSpec().ClearDirectory(); |
819 | reexport_module_sp = |
820 | target.GetImages().FindFirstModule(module_spec: reexport_module_spec); |
821 | } |
822 | } |
823 | // Don't allow us to try and resolve a re-exported symbol if it |
824 | // is the same as the current symbol |
825 | if (name == symbol->GetReExportedSymbolName() && |
826 | module == reexport_module_sp.get()) |
827 | return nullptr; |
828 | |
829 | return FindBestGlobalDataSymbol(name: symbol->GetReExportedSymbolName(), |
830 | error); |
831 | } |
832 | } break; |
833 | |
834 | case eSymbolTypeCode: // We already lookup functions elsewhere |
835 | case eSymbolTypeVariable: |
836 | case eSymbolTypeLocal: |
837 | case eSymbolTypeParam: |
838 | case eSymbolTypeTrampoline: |
839 | case eSymbolTypeInvalid: |
840 | case eSymbolTypeException: |
841 | case eSymbolTypeSourceFile: |
842 | case eSymbolTypeHeaderFile: |
843 | case eSymbolTypeObjectFile: |
844 | case eSymbolTypeCommonBlock: |
845 | case eSymbolTypeBlock: |
846 | case eSymbolTypeVariableType: |
847 | case eSymbolTypeLineEntry: |
848 | case eSymbolTypeLineHeader: |
849 | case eSymbolTypeScopeBegin: |
850 | case eSymbolTypeScopeEnd: |
851 | case eSymbolTypeAdditional: |
852 | case eSymbolTypeCompiler: |
853 | case eSymbolTypeInstrumentation: |
854 | case eSymbolTypeUndefined: |
855 | case eSymbolTypeResolver: |
856 | break; |
857 | } |
858 | } |
859 | } |
860 | } |
861 | |
862 | if (external_symbols.size() > 1) { |
863 | StreamString ss; |
864 | ss.Printf(format: "Multiple external symbols found for '%s'\n" , name.AsCString()); |
865 | for (const Symbol *symbol : external_symbols) { |
866 | symbol->GetDescription(s: &ss, level: eDescriptionLevelFull, target: &target); |
867 | } |
868 | ss.PutChar(ch: '\n'); |
869 | error.SetErrorString(ss.GetData()); |
870 | return nullptr; |
871 | } else if (external_symbols.size()) { |
872 | return external_symbols[0]; |
873 | } else if (internal_symbols.size() > 1) { |
874 | StreamString ss; |
875 | ss.Printf(format: "Multiple internal symbols found for '%s'\n" , name.AsCString()); |
876 | for (const Symbol *symbol : internal_symbols) { |
877 | symbol->GetDescription(s: &ss, level: eDescriptionLevelVerbose, target: &target); |
878 | ss.PutChar(ch: '\n'); |
879 | } |
880 | error.SetErrorString(ss.GetData()); |
881 | return nullptr; |
882 | } else if (internal_symbols.size()) { |
883 | return internal_symbols[0]; |
884 | } else { |
885 | return nullptr; |
886 | } |
887 | }; |
888 | |
889 | if (module) { |
890 | SymbolContextList sc_list; |
891 | module->FindSymbolsWithNameAndType(name, symbol_type: eSymbolTypeAny, sc_list); |
892 | const Symbol *const module_symbol = ProcessMatches(sc_list, error); |
893 | |
894 | if (!error.Success()) { |
895 | return nullptr; |
896 | } else if (module_symbol) { |
897 | return module_symbol; |
898 | } |
899 | } |
900 | |
901 | { |
902 | SymbolContextList sc_list; |
903 | target.GetImages().FindSymbolsWithNameAndType(name, symbol_type: eSymbolTypeAny, |
904 | sc_list); |
905 | const Symbol *const target_symbol = ProcessMatches(sc_list, error); |
906 | |
907 | if (!error.Success()) { |
908 | return nullptr; |
909 | } else if (target_symbol) { |
910 | return target_symbol; |
911 | } |
912 | } |
913 | |
914 | return nullptr; // no error; we just didn't find anything |
915 | } |
916 | |
917 | // |
918 | // SymbolContextSpecifier |
919 | // |
920 | |
921 | SymbolContextSpecifier::SymbolContextSpecifier(const TargetSP &target_sp) |
922 | : m_target_sp(target_sp), m_module_spec(), m_module_sp(), m_file_spec_up(), |
923 | m_start_line(0), m_end_line(0), m_function_spec(), m_class_name(), |
924 | m_address_range_up(), m_type(eNothingSpecified) {} |
925 | |
926 | SymbolContextSpecifier::~SymbolContextSpecifier() = default; |
927 | |
928 | bool SymbolContextSpecifier::AddLineSpecification(uint32_t line_no, |
929 | SpecificationType type) { |
930 | bool return_value = true; |
931 | switch (type) { |
932 | case eNothingSpecified: |
933 | Clear(); |
934 | break; |
935 | case eLineStartSpecified: |
936 | m_start_line = line_no; |
937 | m_type |= eLineStartSpecified; |
938 | break; |
939 | case eLineEndSpecified: |
940 | m_end_line = line_no; |
941 | m_type |= eLineEndSpecified; |
942 | break; |
943 | default: |
944 | return_value = false; |
945 | break; |
946 | } |
947 | return return_value; |
948 | } |
949 | |
950 | bool SymbolContextSpecifier::AddSpecification(const char *spec_string, |
951 | SpecificationType type) { |
952 | bool return_value = true; |
953 | switch (type) { |
954 | case eNothingSpecified: |
955 | Clear(); |
956 | break; |
957 | case eModuleSpecified: { |
958 | // See if we can find the Module, if so stick it in the SymbolContext. |
959 | FileSpec module_file_spec(spec_string); |
960 | ModuleSpec module_spec(module_file_spec); |
961 | lldb::ModuleSP module_sp = |
962 | m_target_sp ? m_target_sp->GetImages().FindFirstModule(module_spec) |
963 | : nullptr; |
964 | m_type |= eModuleSpecified; |
965 | if (module_sp) |
966 | m_module_sp = module_sp; |
967 | else |
968 | m_module_spec.assign(s: spec_string); |
969 | } break; |
970 | case eFileSpecified: |
971 | // CompUnits can't necessarily be resolved here, since an inlined function |
972 | // might show up in a number of CompUnits. Instead we just convert to a |
973 | // FileSpec and store it away. |
974 | m_file_spec_up = std::make_unique<FileSpec>(args&: spec_string); |
975 | m_type |= eFileSpecified; |
976 | break; |
977 | case eLineStartSpecified: |
978 | if ((return_value = llvm::to_integer(S: spec_string, Num&: m_start_line))) |
979 | m_type |= eLineStartSpecified; |
980 | break; |
981 | case eLineEndSpecified: |
982 | if ((return_value = llvm::to_integer(S: spec_string, Num&: m_end_line))) |
983 | m_type |= eLineEndSpecified; |
984 | break; |
985 | case eFunctionSpecified: |
986 | m_function_spec.assign(s: spec_string); |
987 | m_type |= eFunctionSpecified; |
988 | break; |
989 | case eClassOrNamespaceSpecified: |
990 | Clear(); |
991 | m_class_name.assign(s: spec_string); |
992 | m_type = eClassOrNamespaceSpecified; |
993 | break; |
994 | case eAddressRangeSpecified: |
995 | // Not specified yet... |
996 | break; |
997 | } |
998 | |
999 | return return_value; |
1000 | } |
1001 | |
1002 | void SymbolContextSpecifier::Clear() { |
1003 | m_module_spec.clear(); |
1004 | m_file_spec_up.reset(); |
1005 | m_function_spec.clear(); |
1006 | m_class_name.clear(); |
1007 | m_start_line = 0; |
1008 | m_end_line = 0; |
1009 | m_address_range_up.reset(); |
1010 | |
1011 | m_type = eNothingSpecified; |
1012 | } |
1013 | |
1014 | bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext &sc) { |
1015 | if (m_type == eNothingSpecified) |
1016 | return true; |
1017 | |
1018 | // Only compare targets if this specifier has one and it's not the Dummy |
1019 | // target. Otherwise if a specifier gets made in the dummy target and |
1020 | // copied over we'll artificially fail the comparision. |
1021 | if (m_target_sp && !m_target_sp->IsDummyTarget() && |
1022 | m_target_sp != sc.target_sp) |
1023 | return false; |
1024 | |
1025 | if (m_type & eModuleSpecified) { |
1026 | if (sc.module_sp) { |
1027 | if (m_module_sp.get() != nullptr) { |
1028 | if (m_module_sp.get() != sc.module_sp.get()) |
1029 | return false; |
1030 | } else { |
1031 | FileSpec module_file_spec(m_module_spec); |
1032 | if (!FileSpec::Match(pattern: module_file_spec, file: sc.module_sp->GetFileSpec())) |
1033 | return false; |
1034 | } |
1035 | } |
1036 | } |
1037 | if (m_type & eFileSpecified) { |
1038 | if (m_file_spec_up) { |
1039 | // If we don't have a block or a comp_unit, then we aren't going to match |
1040 | // a source file. |
1041 | if (sc.block == nullptr && sc.comp_unit == nullptr) |
1042 | return false; |
1043 | |
1044 | // Check if the block is present, and if so is it inlined: |
1045 | bool was_inlined = false; |
1046 | if (sc.block != nullptr) { |
1047 | const InlineFunctionInfo *inline_info = |
1048 | sc.block->GetInlinedFunctionInfo(); |
1049 | if (inline_info != nullptr) { |
1050 | was_inlined = true; |
1051 | if (!FileSpec::Match(pattern: *m_file_spec_up, |
1052 | file: inline_info->GetDeclaration().GetFile())) |
1053 | return false; |
1054 | } |
1055 | } |
1056 | |
1057 | // Next check the comp unit, but only if the SymbolContext was not |
1058 | // inlined. |
1059 | if (!was_inlined && sc.comp_unit != nullptr) { |
1060 | if (!FileSpec::Match(pattern: *m_file_spec_up, file: sc.comp_unit->GetPrimaryFile())) |
1061 | return false; |
1062 | } |
1063 | } |
1064 | } |
1065 | if (m_type & eLineStartSpecified || m_type & eLineEndSpecified) { |
1066 | if (sc.line_entry.line < m_start_line || sc.line_entry.line > m_end_line) |
1067 | return false; |
1068 | } |
1069 | |
1070 | if (m_type & eFunctionSpecified) { |
1071 | // First check the current block, and if it is inlined, get the inlined |
1072 | // function name: |
1073 | bool was_inlined = false; |
1074 | ConstString func_name(m_function_spec.c_str()); |
1075 | |
1076 | if (sc.block != nullptr) { |
1077 | const InlineFunctionInfo *inline_info = |
1078 | sc.block->GetInlinedFunctionInfo(); |
1079 | if (inline_info != nullptr) { |
1080 | was_inlined = true; |
1081 | const Mangled &name = inline_info->GetMangled(); |
1082 | if (!name.NameMatches(name: func_name)) |
1083 | return false; |
1084 | } |
1085 | } |
1086 | // If it wasn't inlined, check the name in the function or symbol: |
1087 | if (!was_inlined) { |
1088 | if (sc.function != nullptr) { |
1089 | if (!sc.function->GetMangled().NameMatches(name: func_name)) |
1090 | return false; |
1091 | } else if (sc.symbol != nullptr) { |
1092 | if (!sc.symbol->GetMangled().NameMatches(name: func_name)) |
1093 | return false; |
1094 | } |
1095 | } |
1096 | } |
1097 | |
1098 | return true; |
1099 | } |
1100 | |
1101 | bool SymbolContextSpecifier::AddressMatches(lldb::addr_t addr) { |
1102 | if (m_type & eAddressRangeSpecified) { |
1103 | |
1104 | } else { |
1105 | Address match_address(addr, nullptr); |
1106 | SymbolContext sc; |
1107 | m_target_sp->GetImages().ResolveSymbolContextForAddress( |
1108 | so_addr: match_address, resolve_scope: eSymbolContextEverything, sc); |
1109 | return SymbolContextMatches(sc); |
1110 | } |
1111 | return true; |
1112 | } |
1113 | |
1114 | void SymbolContextSpecifier::GetDescription( |
1115 | Stream *s, lldb::DescriptionLevel level) const { |
1116 | char path_str[PATH_MAX + 1]; |
1117 | |
1118 | if (m_type == eNothingSpecified) { |
1119 | s->Printf(format: "Nothing specified.\n" ); |
1120 | } |
1121 | |
1122 | if (m_type == eModuleSpecified) { |
1123 | s->Indent(); |
1124 | if (m_module_sp) { |
1125 | m_module_sp->GetFileSpec().GetPath(path: path_str, PATH_MAX); |
1126 | s->Printf(format: "Module: %s\n" , path_str); |
1127 | } else |
1128 | s->Printf(format: "Module: %s\n" , m_module_spec.c_str()); |
1129 | } |
1130 | |
1131 | if (m_type == eFileSpecified && m_file_spec_up != nullptr) { |
1132 | m_file_spec_up->GetPath(path: path_str, PATH_MAX); |
1133 | s->Indent(); |
1134 | s->Printf(format: "File: %s" , path_str); |
1135 | if (m_type == eLineStartSpecified) { |
1136 | s->Printf(format: " from line %" PRIu64 "" , (uint64_t)m_start_line); |
1137 | if (m_type == eLineEndSpecified) |
1138 | s->Printf(format: "to line %" PRIu64 "" , (uint64_t)m_end_line); |
1139 | else |
1140 | s->Printf(format: "to end" ); |
1141 | } else if (m_type == eLineEndSpecified) { |
1142 | s->Printf(format: " from start to line %" PRIu64 "" , (uint64_t)m_end_line); |
1143 | } |
1144 | s->Printf(format: ".\n" ); |
1145 | } |
1146 | |
1147 | if (m_type == eLineStartSpecified) { |
1148 | s->Indent(); |
1149 | s->Printf(format: "From line %" PRIu64 "" , (uint64_t)m_start_line); |
1150 | if (m_type == eLineEndSpecified) |
1151 | s->Printf(format: "to line %" PRIu64 "" , (uint64_t)m_end_line); |
1152 | else |
1153 | s->Printf(format: "to end" ); |
1154 | s->Printf(format: ".\n" ); |
1155 | } else if (m_type == eLineEndSpecified) { |
1156 | s->Printf(format: "From start to line %" PRIu64 ".\n" , (uint64_t)m_end_line); |
1157 | } |
1158 | |
1159 | if (m_type == eFunctionSpecified) { |
1160 | s->Indent(); |
1161 | s->Printf(format: "Function: %s.\n" , m_function_spec.c_str()); |
1162 | } |
1163 | |
1164 | if (m_type == eClassOrNamespaceSpecified) { |
1165 | s->Indent(); |
1166 | s->Printf(format: "Class name: %s.\n" , m_class_name.c_str()); |
1167 | } |
1168 | |
1169 | if (m_type == eAddressRangeSpecified && m_address_range_up != nullptr) { |
1170 | s->Indent(); |
1171 | s->PutCString(cstr: "Address range: " ); |
1172 | m_address_range_up->Dump(s, target: m_target_sp.get(), |
1173 | style: Address::DumpStyleLoadAddress, |
1174 | fallback_style: Address::DumpStyleFileAddress); |
1175 | s->PutCString(cstr: "\n" ); |
1176 | } |
1177 | } |
1178 | |
1179 | // |
1180 | // SymbolContextList |
1181 | // |
1182 | |
1183 | SymbolContextList::SymbolContextList() : m_symbol_contexts() {} |
1184 | |
1185 | SymbolContextList::~SymbolContextList() = default; |
1186 | |
1187 | void SymbolContextList::Append(const SymbolContext &sc) { |
1188 | m_symbol_contexts.push_back(x: sc); |
1189 | } |
1190 | |
1191 | void SymbolContextList::Append(const SymbolContextList &sc_list) { |
1192 | collection::const_iterator pos, end = sc_list.m_symbol_contexts.end(); |
1193 | for (pos = sc_list.m_symbol_contexts.begin(); pos != end; ++pos) |
1194 | m_symbol_contexts.push_back(x: *pos); |
1195 | } |
1196 | |
1197 | uint32_t SymbolContextList::AppendIfUnique(const SymbolContextList &sc_list, |
1198 | bool merge_symbol_into_function) { |
1199 | uint32_t unique_sc_add_count = 0; |
1200 | collection::const_iterator pos, end = sc_list.m_symbol_contexts.end(); |
1201 | for (pos = sc_list.m_symbol_contexts.begin(); pos != end; ++pos) { |
1202 | if (AppendIfUnique(sc: *pos, merge_symbol_into_function)) |
1203 | ++unique_sc_add_count; |
1204 | } |
1205 | return unique_sc_add_count; |
1206 | } |
1207 | |
1208 | bool SymbolContextList::AppendIfUnique(const SymbolContext &sc, |
1209 | bool merge_symbol_into_function) { |
1210 | collection::iterator pos, end = m_symbol_contexts.end(); |
1211 | for (pos = m_symbol_contexts.begin(); pos != end; ++pos) { |
1212 | if (*pos == sc) |
1213 | return false; |
1214 | } |
1215 | if (merge_symbol_into_function && sc.symbol != nullptr && |
1216 | sc.comp_unit == nullptr && sc.function == nullptr && |
1217 | sc.block == nullptr && !sc.line_entry.IsValid()) { |
1218 | if (sc.symbol->ValueIsAddress()) { |
1219 | for (pos = m_symbol_contexts.begin(); pos != end; ++pos) { |
1220 | // Don't merge symbols into inlined function symbol contexts |
1221 | if (pos->block && pos->block->GetContainingInlinedBlock()) |
1222 | continue; |
1223 | |
1224 | if (pos->function) { |
1225 | if (pos->function->GetAddressRange().GetBaseAddress() == |
1226 | sc.symbol->GetAddressRef()) { |
1227 | // Do we already have a function with this symbol? |
1228 | if (pos->symbol == sc.symbol) |
1229 | return false; |
1230 | if (pos->symbol == nullptr) { |
1231 | pos->symbol = sc.symbol; |
1232 | return false; |
1233 | } |
1234 | } |
1235 | } |
1236 | } |
1237 | } |
1238 | } |
1239 | m_symbol_contexts.push_back(x: sc); |
1240 | return true; |
1241 | } |
1242 | |
1243 | void SymbolContextList::Clear() { m_symbol_contexts.clear(); } |
1244 | |
1245 | void SymbolContextList::Dump(Stream *s, Target *target) const { |
1246 | |
1247 | *s << this << ": " ; |
1248 | s->Indent(); |
1249 | s->PutCString(cstr: "SymbolContextList" ); |
1250 | s->EOL(); |
1251 | s->IndentMore(); |
1252 | |
1253 | collection::const_iterator pos, end = m_symbol_contexts.end(); |
1254 | for (pos = m_symbol_contexts.begin(); pos != end; ++pos) { |
1255 | // pos->Dump(s, target); |
1256 | pos->GetDescription(s, level: eDescriptionLevelVerbose, target); |
1257 | } |
1258 | s->IndentLess(); |
1259 | } |
1260 | |
1261 | bool SymbolContextList::GetContextAtIndex(size_t idx, SymbolContext &sc) const { |
1262 | if (idx < m_symbol_contexts.size()) { |
1263 | sc = m_symbol_contexts[idx]; |
1264 | return true; |
1265 | } |
1266 | return false; |
1267 | } |
1268 | |
1269 | bool SymbolContextList::RemoveContextAtIndex(size_t idx) { |
1270 | if (idx < m_symbol_contexts.size()) { |
1271 | m_symbol_contexts.erase(position: m_symbol_contexts.begin() + idx); |
1272 | return true; |
1273 | } |
1274 | return false; |
1275 | } |
1276 | |
1277 | uint32_t SymbolContextList::GetSize() const { return m_symbol_contexts.size(); } |
1278 | |
1279 | bool SymbolContextList::IsEmpty() const { return m_symbol_contexts.empty(); } |
1280 | |
1281 | uint32_t SymbolContextList::NumLineEntriesWithLine(uint32_t line) const { |
1282 | uint32_t match_count = 0; |
1283 | const size_t size = m_symbol_contexts.size(); |
1284 | for (size_t idx = 0; idx < size; ++idx) { |
1285 | if (m_symbol_contexts[idx].line_entry.line == line) |
1286 | ++match_count; |
1287 | } |
1288 | return match_count; |
1289 | } |
1290 | |
1291 | void SymbolContextList::GetDescription(Stream *s, lldb::DescriptionLevel level, |
1292 | Target *target) const { |
1293 | const size_t size = m_symbol_contexts.size(); |
1294 | for (size_t idx = 0; idx < size; ++idx) |
1295 | m_symbol_contexts[idx].GetDescription(s, level, target); |
1296 | } |
1297 | |
1298 | bool lldb_private::operator==(const SymbolContextList &lhs, |
1299 | const SymbolContextList &rhs) { |
1300 | const uint32_t size = lhs.GetSize(); |
1301 | if (size != rhs.GetSize()) |
1302 | return false; |
1303 | |
1304 | SymbolContext lhs_sc; |
1305 | SymbolContext rhs_sc; |
1306 | for (uint32_t i = 0; i < size; ++i) { |
1307 | lhs.GetContextAtIndex(idx: i, sc&: lhs_sc); |
1308 | rhs.GetContextAtIndex(idx: i, sc&: rhs_sc); |
1309 | if (lhs_sc != rhs_sc) |
1310 | return false; |
1311 | } |
1312 | return true; |
1313 | } |
1314 | |
1315 | bool lldb_private::operator!=(const SymbolContextList &lhs, |
1316 | const SymbolContextList &rhs) { |
1317 | return !(lhs == rhs); |
1318 | } |
1319 | |