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