diff options
Diffstat (limited to 'lldb/source/Symbol/Function.cpp')
| -rw-r--r-- | lldb/source/Symbol/Function.cpp | 623 | 
1 files changed, 623 insertions, 0 deletions
| diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp new file mode 100644 index 000000000000..a4c2d3b4b44a --- /dev/null +++ b/lldb/source/Symbol/Function.cpp @@ -0,0 +1,623 @@ +//===-- Function.cpp --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/Function.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/Section.h" +#include "lldb/Host/Host.h" +#include "lldb/Symbol/CompileUnit.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Target/Language.h" +#include "lldb/Utility/Log.h" +#include "llvm/Support/Casting.h" + +using namespace lldb; +using namespace lldb_private; + +// Basic function information is contained in the FunctionInfo class. It is +// designed to contain the name, linkage name, and declaration location. +FunctionInfo::FunctionInfo(const char *name, const Declaration *decl_ptr) +    : m_name(name), m_declaration(decl_ptr) {} + +FunctionInfo::FunctionInfo(ConstString name, const Declaration *decl_ptr) +    : m_name(name), m_declaration(decl_ptr) {} + +FunctionInfo::~FunctionInfo() {} + +void FunctionInfo::Dump(Stream *s, bool show_fullpaths) const { +  if (m_name) +    *s << ", name = \"" << m_name << "\""; +  m_declaration.Dump(s, show_fullpaths); +} + +int FunctionInfo::Compare(const FunctionInfo &a, const FunctionInfo &b) { +  int result = ConstString::Compare(a.GetName(), b.GetName()); +  if (result) +    return result; + +  return Declaration::Compare(a.m_declaration, b.m_declaration); +} + +Declaration &FunctionInfo::GetDeclaration() { return m_declaration; } + +const Declaration &FunctionInfo::GetDeclaration() const { +  return m_declaration; +} + +ConstString FunctionInfo::GetName() const { return m_name; } + +size_t FunctionInfo::MemorySize() const { +  return m_name.MemorySize() + m_declaration.MemorySize(); +} + +InlineFunctionInfo::InlineFunctionInfo(const char *name, +                                       llvm::StringRef mangled, +                                       const Declaration *decl_ptr, +                                       const Declaration *call_decl_ptr) +    : FunctionInfo(name, decl_ptr), m_mangled(mangled), +      m_call_decl(call_decl_ptr) {} + +InlineFunctionInfo::InlineFunctionInfo(ConstString name, +                                       const Mangled &mangled, +                                       const Declaration *decl_ptr, +                                       const Declaration *call_decl_ptr) +    : FunctionInfo(name, decl_ptr), m_mangled(mangled), +      m_call_decl(call_decl_ptr) {} + +InlineFunctionInfo::~InlineFunctionInfo() {} + +int InlineFunctionInfo::Compare(const InlineFunctionInfo &a, +                                const InlineFunctionInfo &b) { + +  int result = FunctionInfo::Compare(a, b); +  if (result) +    return result; +  // only compare the mangled names if both have them +  return Mangled::Compare(a.m_mangled, a.m_mangled); +} + +void InlineFunctionInfo::Dump(Stream *s, bool show_fullpaths) const { +  FunctionInfo::Dump(s, show_fullpaths); +  if (m_mangled) +    m_mangled.Dump(s); +} + +void InlineFunctionInfo::DumpStopContext(Stream *s, +                                         LanguageType language) const { +  //    s->Indent("[inlined] "); +  s->Indent(); +  if (m_mangled) +    s->PutCString(m_mangled.GetName(language).AsCString()); +  else +    s->PutCString(m_name.AsCString()); +} + +ConstString InlineFunctionInfo::GetName(LanguageType language) const { +  if (m_mangled) +    return m_mangled.GetName(language); +  return m_name; +} + +ConstString InlineFunctionInfo::GetDisplayName(LanguageType language) const { +  if (m_mangled) +    return m_mangled.GetDisplayDemangledName(language); +  return m_name; +} + +Declaration &InlineFunctionInfo::GetCallSite() { return m_call_decl; } + +const Declaration &InlineFunctionInfo::GetCallSite() const { +  return m_call_decl; +} + +Mangled &InlineFunctionInfo::GetMangled() { return m_mangled; } + +const Mangled &InlineFunctionInfo::GetMangled() const { return m_mangled; } + +size_t InlineFunctionInfo::MemorySize() const { +  return FunctionInfo::MemorySize() + m_mangled.MemorySize(); +} + +// +CallEdge::CallEdge(const char *symbol_name, lldb::addr_t return_pc, +                   CallSiteParameterArray parameters) +    : return_pc(return_pc), parameters(std::move(parameters)), resolved(false) { +  lazy_callee.symbol_name = symbol_name; +} + +llvm::ArrayRef<CallSiteParameter> CallEdge::GetCallSiteParameters() const { +  return parameters; +} + +void CallEdge::ParseSymbolFileAndResolve(ModuleList &images) { +  if (resolved) +    return; + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); +  LLDB_LOG(log, "CallEdge: Lazily parsing the call graph for {0}", +           lazy_callee.symbol_name); + +  auto resolve_lazy_callee = [&]() -> Function * { +    ConstString callee_name{lazy_callee.symbol_name}; +    SymbolContextList sc_list; +    images.FindFunctionSymbols(callee_name, eFunctionNameTypeAuto, sc_list); +    size_t num_matches = sc_list.GetSize(); +    if (num_matches == 0 || !sc_list[0].symbol) { +      LLDB_LOG(log, "CallEdge: Found no symbols for {0}, cannot resolve it", +               callee_name); +      return nullptr; +    } +    Address callee_addr = sc_list[0].symbol->GetAddress(); +    if (!callee_addr.IsValid()) { +      LLDB_LOG(log, "CallEdge: Invalid symbol address"); +      return nullptr; +    } +    Function *f = callee_addr.CalculateSymbolContextFunction(); +    if (!f) { +      LLDB_LOG(log, "CallEdge: Could not find complete function"); +      return nullptr; +    } +    return f; +  }; +  lazy_callee.def = resolve_lazy_callee(); +  resolved = true; +} + +Function *CallEdge::GetCallee(ModuleList &images) { +  ParseSymbolFileAndResolve(images); +  assert(resolved && "Did not resolve lazy callee"); +  return lazy_callee.def; +} + +lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller, +                                          Target &target) const { +  const Address &base = caller.GetAddressRange().GetBaseAddress(); +  return base.GetLoadAddress(&target) + return_pc; +} + +// +Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid, +                   lldb::user_id_t type_uid, const Mangled &mangled, Type *type, +                   const AddressRange &range) +    : UserID(func_uid), m_comp_unit(comp_unit), m_type_uid(type_uid), +      m_type(type), m_mangled(mangled), m_block(func_uid), m_range(range), +      m_frame_base(), m_flags(), m_prologue_byte_size(0) { +  m_block.SetParentScope(this); +  assert(comp_unit != nullptr); +} + +Function::~Function() {} + +void Function::GetStartLineSourceInfo(FileSpec &source_file, +                                      uint32_t &line_no) { +  line_no = 0; +  source_file.Clear(); + +  if (m_comp_unit == nullptr) +    return; + +  // Initialize m_type if it hasn't been initialized already +  GetType(); + +  if (m_type != nullptr && m_type->GetDeclaration().GetLine() != 0) { +    source_file = m_type->GetDeclaration().GetFile(); +    line_no = m_type->GetDeclaration().GetLine(); +  } else { +    LineTable *line_table = m_comp_unit->GetLineTable(); +    if (line_table == nullptr) +      return; + +    LineEntry line_entry; +    if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), +                                           line_entry, nullptr)) { +      line_no = line_entry.line; +      source_file = line_entry.file; +    } +  } +} + +void Function::GetEndLineSourceInfo(FileSpec &source_file, uint32_t &line_no) { +  line_no = 0; +  source_file.Clear(); + +  // The -1 is kind of cheesy, but I want to get the last line entry for the +  // given function, not the first entry of the next. +  Address scratch_addr(GetAddressRange().GetBaseAddress()); +  scratch_addr.SetOffset(scratch_addr.GetOffset() + +                         GetAddressRange().GetByteSize() - 1); + +  LineTable *line_table = m_comp_unit->GetLineTable(); +  if (line_table == nullptr) +    return; + +  LineEntry line_entry; +  if (line_table->FindLineEntryByAddress(scratch_addr, line_entry, nullptr)) { +    line_no = line_entry.line; +    source_file = line_entry.file; +  } +} + +llvm::MutableArrayRef<CallEdge> Function::GetCallEdges() { +  if (m_call_edges_resolved) +    return m_call_edges; + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); +  LLDB_LOG(log, "GetCallEdges: Attempting to parse call site info for {0}", +           GetDisplayName()); + +  m_call_edges_resolved = true; + +  // Find the SymbolFile which provided this function's definition. +  Block &block = GetBlock(/*can_create*/true); +  SymbolFile *sym_file = block.GetSymbolFile(); +  if (!sym_file) +    return llvm::None; + +  // Lazily read call site information from the SymbolFile. +  m_call_edges = sym_file->ParseCallEdgesInFunction(GetID()); + +  // Sort the call edges to speed up return_pc lookups. +  llvm::sort(m_call_edges.begin(), m_call_edges.end(), +             [](const CallEdge &LHS, const CallEdge &RHS) { +               return LHS.GetUnresolvedReturnPCAddress() < +                      RHS.GetUnresolvedReturnPCAddress(); +             }); + +  return m_call_edges; +} + +llvm::MutableArrayRef<CallEdge> Function::GetTailCallingEdges() { +  // Call edges are sorted by return PC, and tail calling edges have invalid +  // return PCs. Find them at the end of the list. +  return GetCallEdges().drop_until([](const CallEdge &edge) { +    return edge.GetUnresolvedReturnPCAddress() == LLDB_INVALID_ADDRESS; +  }); +} + +CallEdge *Function::GetCallEdgeForReturnAddress(addr_t return_pc, +                                                Target &target) { +  auto edges = GetCallEdges(); +  auto edge_it = +      std::lower_bound(edges.begin(), edges.end(), return_pc, +                       [&](const CallEdge &edge, addr_t pc) { +                         return edge.GetReturnPCAddress(*this, target) < pc; +                       }); +  if (edge_it == edges.end() || +      edge_it->GetReturnPCAddress(*this, target) != return_pc) +    return nullptr; +  return &const_cast<CallEdge &>(*edge_it); +} + +Block &Function::GetBlock(bool can_create) { +  if (!m_block.BlockInfoHasBeenParsed() && can_create) { +    ModuleSP module_sp = CalculateSymbolContextModule(); +    if (module_sp) { +      module_sp->GetSymbolFile()->ParseBlocksRecursive(*this); +    } else { +      Host::SystemLog(Host::eSystemLogError, +                      "error: unable to find module " +                      "shared pointer for function '%s' " +                      "in %s\n", +                      GetName().GetCString(), m_comp_unit->GetPath().c_str()); +    } +    m_block.SetBlockInfoHasBeenParsed(true, true); +  } +  return m_block; +} + +CompileUnit *Function::GetCompileUnit() { return m_comp_unit; } + +const CompileUnit *Function::GetCompileUnit() const { return m_comp_unit; } + +void Function::GetDescription(Stream *s, lldb::DescriptionLevel level, +                              Target *target) { +  ConstString name = GetName(); +  ConstString mangled = m_mangled.GetMangledName(); + +  *s << "id = " << (const UserID &)*this; +  if (name) +    *s << ", name = \"" << name.GetCString() << '"'; +  if (mangled) +    *s << ", mangled = \"" << mangled.GetCString() << '"'; +  *s << ", range = "; +  Address::DumpStyle fallback_style; +  if (level == eDescriptionLevelVerbose) +    fallback_style = Address::DumpStyleModuleWithFileAddress; +  else +    fallback_style = Address::DumpStyleFileAddress; +  GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, +                         fallback_style); +} + +void Function::Dump(Stream *s, bool show_context) const { +  s->Printf("%p: ", static_cast<const void *>(this)); +  s->Indent(); +  *s << "Function" << static_cast<const UserID &>(*this); + +  m_mangled.Dump(s); + +  if (m_type) +    s->Printf(", type = %p", static_cast<void *>(m_type)); +  else if (m_type_uid != LLDB_INVALID_UID) +    s->Printf(", type_uid = 0x%8.8" PRIx64, m_type_uid); + +  s->EOL(); +  // Dump the root object +  if (m_block.BlockInfoHasBeenParsed()) +    m_block.Dump(s, m_range.GetBaseAddress().GetFileAddress(), INT_MAX, +                 show_context); +} + +void Function::CalculateSymbolContext(SymbolContext *sc) { +  sc->function = this; +  m_comp_unit->CalculateSymbolContext(sc); +} + +ModuleSP Function::CalculateSymbolContextModule() { +  SectionSP section_sp(m_range.GetBaseAddress().GetSection()); +  if (section_sp) +    return section_sp->GetModule(); + +  return this->GetCompileUnit()->GetModule(); +} + +CompileUnit *Function::CalculateSymbolContextCompileUnit() { +  return this->GetCompileUnit(); +} + +Function *Function::CalculateSymbolContextFunction() { return this; } + +lldb::DisassemblerSP Function::GetInstructions(const ExecutionContext &exe_ctx, +                                               const char *flavor, +                                               bool prefer_file_cache) { +  ModuleSP module_sp(GetAddressRange().GetBaseAddress().GetModule()); +  if (module_sp) { +    const bool prefer_file_cache = false; +    return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr, +                                          flavor, exe_ctx, GetAddressRange(), +                                          prefer_file_cache); +  } +  return lldb::DisassemblerSP(); +} + +bool Function::GetDisassembly(const ExecutionContext &exe_ctx, +                              const char *flavor, bool prefer_file_cache, +                              Stream &strm) { +  lldb::DisassemblerSP disassembler_sp = +      GetInstructions(exe_ctx, flavor, prefer_file_cache); +  if (disassembler_sp) { +    const bool show_address = true; +    const bool show_bytes = false; +    disassembler_sp->GetInstructionList().Dump(&strm, show_address, show_bytes, +                                               &exe_ctx); +    return true; +  } +  return false; +} + +// Symbol * +// Function::CalculateSymbolContextSymbol () +//{ +//    return // TODO: find the symbol for the function??? +//} + +void Function::DumpSymbolContext(Stream *s) { +  m_comp_unit->DumpSymbolContext(s); +  s->Printf(", Function{0x%8.8" PRIx64 "}", GetID()); +} + +size_t Function::MemorySize() const { +  size_t mem_size = sizeof(Function) + m_block.MemorySize(); +  return mem_size; +} + +bool Function::GetIsOptimized() { +  bool result = false; + +  // Currently optimization is only indicted by the vendor extension +  // DW_AT_APPLE_optimized which is set on a compile unit level. +  if (m_comp_unit) { +    result = m_comp_unit->GetIsOptimized(); +  } +  return result; +} + +bool Function::IsTopLevelFunction() { +  bool result = false; + +  if (Language *language = Language::FindPlugin(GetLanguage())) +    result = language->IsTopLevelFunction(*this); + +  return result; +} + +ConstString Function::GetDisplayName() const { +  return m_mangled.GetDisplayDemangledName(GetLanguage()); +} + +CompilerDeclContext Function::GetDeclContext() { +  ModuleSP module_sp = CalculateSymbolContextModule(); + +  if (module_sp) { +    if (SymbolFile *sym_file = module_sp->GetSymbolFile()) +      return sym_file->GetDeclContextForUID(GetID()); +  } +  return CompilerDeclContext(); +} + +Type *Function::GetType() { +  if (m_type == nullptr) { +    SymbolContext sc; + +    CalculateSymbolContext(&sc); + +    if (!sc.module_sp) +      return nullptr; + +    SymbolFile *sym_file = sc.module_sp->GetSymbolFile(); + +    if (sym_file == nullptr) +      return nullptr; + +    m_type = sym_file->ResolveTypeUID(m_type_uid); +  } +  return m_type; +} + +const Type *Function::GetType() const { return m_type; } + +CompilerType Function::GetCompilerType() { +  Type *function_type = GetType(); +  if (function_type) +    return function_type->GetFullCompilerType(); +  return CompilerType(); +} + +uint32_t Function::GetPrologueByteSize() { +  if (m_prologue_byte_size == 0 && +      m_flags.IsClear(flagsCalculatedPrologueSize)) { +    m_flags.Set(flagsCalculatedPrologueSize); +    LineTable *line_table = m_comp_unit->GetLineTable(); +    uint32_t prologue_end_line_idx = 0; + +    if (line_table) { +      LineEntry first_line_entry; +      uint32_t first_line_entry_idx = UINT32_MAX; +      if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), +                                             first_line_entry, +                                             &first_line_entry_idx)) { +        // Make sure the first line entry isn't already the end of the prologue +        addr_t prologue_end_file_addr = LLDB_INVALID_ADDRESS; +        addr_t line_zero_end_file_addr = LLDB_INVALID_ADDRESS; + +        if (first_line_entry.is_prologue_end) { +          prologue_end_file_addr = +              first_line_entry.range.GetBaseAddress().GetFileAddress(); +          prologue_end_line_idx = first_line_entry_idx; +        } else { +          // Check the first few instructions and look for one that has +          // is_prologue_end set to true. +          const uint32_t last_line_entry_idx = first_line_entry_idx + 6; +          for (uint32_t idx = first_line_entry_idx + 1; +               idx < last_line_entry_idx; ++idx) { +            LineEntry line_entry; +            if (line_table->GetLineEntryAtIndex(idx, line_entry)) { +              if (line_entry.is_prologue_end) { +                prologue_end_file_addr = +                    line_entry.range.GetBaseAddress().GetFileAddress(); +                prologue_end_line_idx = idx; +                break; +              } +            } +          } +        } + +        // If we didn't find the end of the prologue in the line tables, then +        // just use the end address of the first line table entry +        if (prologue_end_file_addr == LLDB_INVALID_ADDRESS) { +          // Check the first few instructions and look for one that has a line +          // number that's different than the first entry. +          uint32_t last_line_entry_idx = first_line_entry_idx + 6; +          for (uint32_t idx = first_line_entry_idx + 1; +               idx < last_line_entry_idx; ++idx) { +            LineEntry line_entry; +            if (line_table->GetLineEntryAtIndex(idx, line_entry)) { +              if (line_entry.line != first_line_entry.line) { +                prologue_end_file_addr = +                    line_entry.range.GetBaseAddress().GetFileAddress(); +                prologue_end_line_idx = idx; +                break; +              } +            } +          } + +          if (prologue_end_file_addr == LLDB_INVALID_ADDRESS) { +            prologue_end_file_addr = +                first_line_entry.range.GetBaseAddress().GetFileAddress() + +                first_line_entry.range.GetByteSize(); +            prologue_end_line_idx = first_line_entry_idx; +          } +        } + +        const addr_t func_start_file_addr = +            m_range.GetBaseAddress().GetFileAddress(); +        const addr_t func_end_file_addr = +            func_start_file_addr + m_range.GetByteSize(); + +        // Now calculate the offset to pass the subsequent line 0 entries. +        uint32_t first_non_zero_line = prologue_end_line_idx; +        while (true) { +          LineEntry line_entry; +          if (line_table->GetLineEntryAtIndex(first_non_zero_line, +                                              line_entry)) { +            if (line_entry.line != 0) +              break; +          } +          if (line_entry.range.GetBaseAddress().GetFileAddress() >= +              func_end_file_addr) +            break; + +          first_non_zero_line++; +        } + +        if (first_non_zero_line > prologue_end_line_idx) { +          LineEntry first_non_zero_entry; +          if (line_table->GetLineEntryAtIndex(first_non_zero_line, +                                              first_non_zero_entry)) { +            line_zero_end_file_addr = +                first_non_zero_entry.range.GetBaseAddress().GetFileAddress(); +          } +        } + +        // Verify that this prologue end file address in the function's address +        // range just to be sure +        if (func_start_file_addr < prologue_end_file_addr && +            prologue_end_file_addr < func_end_file_addr) { +          m_prologue_byte_size = prologue_end_file_addr - func_start_file_addr; +        } + +        if (prologue_end_file_addr < line_zero_end_file_addr && +            line_zero_end_file_addr < func_end_file_addr) { +          m_prologue_byte_size += +              line_zero_end_file_addr - prologue_end_file_addr; +        } +      } +    } +  } + +  return m_prologue_byte_size; +} + +lldb::LanguageType Function::GetLanguage() const { +  lldb::LanguageType lang = m_mangled.GuessLanguage(); +  if (lang != lldb::eLanguageTypeUnknown) +    return lang; + +  if (m_comp_unit) +    return m_comp_unit->GetLanguage(); + +  return lldb::eLanguageTypeUnknown; +} + +ConstString Function::GetName() const { +  LanguageType language = lldb::eLanguageTypeUnknown; +  if (m_comp_unit) +    language = m_comp_unit->GetLanguage(); +  return m_mangled.GetName(language); +} + +ConstString Function::GetNameNoArguments() const { +  LanguageType language = lldb::eLanguageTypeUnknown; +  if (m_comp_unit) +    language = m_comp_unit->GetLanguage(); +  return m_mangled.GetName(language, Mangled::ePreferDemangledWithoutArguments); +} | 
