Path: blob/main/contrib/llvm-project/lldb/source/Symbol/Function.cpp
39587 views
//===-- Function.cpp ------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Symbol/Function.h"9#include "lldb/Core/Debugger.h"10#include "lldb/Core/Disassembler.h"11#include "lldb/Core/Module.h"12#include "lldb/Core/ModuleList.h"13#include "lldb/Core/Section.h"14#include "lldb/Host/Host.h"15#include "lldb/Symbol/CompileUnit.h"16#include "lldb/Symbol/CompilerType.h"17#include "lldb/Symbol/LineTable.h"18#include "lldb/Symbol/SymbolFile.h"19#include "lldb/Target/Language.h"20#include "lldb/Target/Target.h"21#include "lldb/Utility/LLDBLog.h"22#include "lldb/Utility/Log.h"23#include "llvm/Support/Casting.h"2425using namespace lldb;26using namespace lldb_private;2728// Basic function information is contained in the FunctionInfo class. It is29// designed to contain the name, linkage name, and declaration location.30FunctionInfo::FunctionInfo(const char *name, const Declaration *decl_ptr)31: m_name(name), m_declaration(decl_ptr) {}3233FunctionInfo::FunctionInfo(ConstString name, const Declaration *decl_ptr)34: m_name(name), m_declaration(decl_ptr) {}3536FunctionInfo::~FunctionInfo() = default;3738void FunctionInfo::Dump(Stream *s, bool show_fullpaths) const {39if (m_name)40*s << ", name = \"" << m_name << "\"";41m_declaration.Dump(s, show_fullpaths);42}4344int FunctionInfo::Compare(const FunctionInfo &a, const FunctionInfo &b) {45int result = ConstString::Compare(a.GetName(), b.GetName());46if (result)47return result;4849return Declaration::Compare(a.m_declaration, b.m_declaration);50}5152Declaration &FunctionInfo::GetDeclaration() { return m_declaration; }5354const Declaration &FunctionInfo::GetDeclaration() const {55return m_declaration;56}5758ConstString FunctionInfo::GetName() const { return m_name; }5960size_t FunctionInfo::MemorySize() const {61return m_name.MemorySize() + m_declaration.MemorySize();62}6364InlineFunctionInfo::InlineFunctionInfo(const char *name,65llvm::StringRef mangled,66const Declaration *decl_ptr,67const Declaration *call_decl_ptr)68: FunctionInfo(name, decl_ptr), m_mangled(mangled),69m_call_decl(call_decl_ptr) {}7071InlineFunctionInfo::InlineFunctionInfo(ConstString name,72const Mangled &mangled,73const Declaration *decl_ptr,74const Declaration *call_decl_ptr)75: FunctionInfo(name, decl_ptr), m_mangled(mangled),76m_call_decl(call_decl_ptr) {}7778InlineFunctionInfo::~InlineFunctionInfo() = default;7980void InlineFunctionInfo::Dump(Stream *s, bool show_fullpaths) const {81FunctionInfo::Dump(s, show_fullpaths);82if (m_mangled)83m_mangled.Dump(s);84}8586void InlineFunctionInfo::DumpStopContext(Stream *s) const {87// s->Indent("[inlined] ");88s->Indent();89if (m_mangled)90s->PutCString(m_mangled.GetName().AsCString());91else92s->PutCString(m_name.AsCString());93}9495ConstString InlineFunctionInfo::GetName() const {96if (m_mangled)97return m_mangled.GetName();98return m_name;99}100101ConstString InlineFunctionInfo::GetDisplayName() const {102if (m_mangled)103return m_mangled.GetDisplayDemangledName();104return m_name;105}106107Declaration &InlineFunctionInfo::GetCallSite() { return m_call_decl; }108109const Declaration &InlineFunctionInfo::GetCallSite() const {110return m_call_decl;111}112113Mangled &InlineFunctionInfo::GetMangled() { return m_mangled; }114115const Mangled &InlineFunctionInfo::GetMangled() const { return m_mangled; }116117size_t InlineFunctionInfo::MemorySize() const {118return FunctionInfo::MemorySize() + m_mangled.MemorySize();119}120121/// @name Call site related structures122/// @{123124CallEdge::~CallEdge() = default;125126CallEdge::CallEdge(AddrType caller_address_type, lldb::addr_t caller_address,127bool is_tail_call, CallSiteParameterArray &¶meters)128: caller_address(caller_address), caller_address_type(caller_address_type),129is_tail_call(is_tail_call), parameters(std::move(parameters)) {}130131lldb::addr_t CallEdge::GetLoadAddress(lldb::addr_t unresolved_pc,132Function &caller, Target &target) {133Log *log = GetLog(LLDBLog::Step);134135const Address &caller_start_addr = caller.GetAddressRange().GetBaseAddress();136137ModuleSP caller_module_sp = caller_start_addr.GetModule();138if (!caller_module_sp) {139LLDB_LOG(log, "GetLoadAddress: cannot get Module for caller");140return LLDB_INVALID_ADDRESS;141}142143SectionList *section_list = caller_module_sp->GetSectionList();144if (!section_list) {145LLDB_LOG(log, "GetLoadAddress: cannot get SectionList for Module");146return LLDB_INVALID_ADDRESS;147}148149Address the_addr = Address(unresolved_pc, section_list);150lldb::addr_t load_addr = the_addr.GetLoadAddress(&target);151return load_addr;152}153154lldb::addr_t CallEdge::GetReturnPCAddress(Function &caller,155Target &target) const {156return GetLoadAddress(GetUnresolvedReturnPCAddress(), caller, target);157}158159void DirectCallEdge::ParseSymbolFileAndResolve(ModuleList &images) {160if (resolved)161return;162163Log *log = GetLog(LLDBLog::Step);164LLDB_LOG(log, "DirectCallEdge: Lazily parsing the call graph for {0}",165lazy_callee.symbol_name);166167auto resolve_lazy_callee = [&]() -> Function * {168ConstString callee_name{lazy_callee.symbol_name};169SymbolContextList sc_list;170images.FindFunctionSymbols(callee_name, eFunctionNameTypeAuto, sc_list);171size_t num_matches = sc_list.GetSize();172if (num_matches == 0 || !sc_list[0].symbol) {173LLDB_LOG(log,174"DirectCallEdge: Found no symbols for {0}, cannot resolve it",175callee_name);176return nullptr;177}178Address callee_addr = sc_list[0].symbol->GetAddress();179if (!callee_addr.IsValid()) {180LLDB_LOG(log, "DirectCallEdge: Invalid symbol address");181return nullptr;182}183Function *f = callee_addr.CalculateSymbolContextFunction();184if (!f) {185LLDB_LOG(log, "DirectCallEdge: Could not find complete function");186return nullptr;187}188return f;189};190lazy_callee.def = resolve_lazy_callee();191resolved = true;192}193194DirectCallEdge::DirectCallEdge(const char *symbol_name,195AddrType caller_address_type,196lldb::addr_t caller_address, bool is_tail_call,197CallSiteParameterArray &¶meters)198: CallEdge(caller_address_type, caller_address, is_tail_call,199std::move(parameters)) {200lazy_callee.symbol_name = symbol_name;201}202203Function *DirectCallEdge::GetCallee(ModuleList &images, ExecutionContext &) {204ParseSymbolFileAndResolve(images);205assert(resolved && "Did not resolve lazy callee");206return lazy_callee.def;207}208209IndirectCallEdge::IndirectCallEdge(DWARFExpressionList call_target,210AddrType caller_address_type,211lldb::addr_t caller_address,212bool is_tail_call,213CallSiteParameterArray &¶meters)214: CallEdge(caller_address_type, caller_address, is_tail_call,215std::move(parameters)),216call_target(std::move(call_target)) {}217218Function *IndirectCallEdge::GetCallee(ModuleList &images,219ExecutionContext &exe_ctx) {220Log *log = GetLog(LLDBLog::Step);221Status error;222llvm::Expected<Value> callee_addr_val = call_target.Evaluate(223&exe_ctx, exe_ctx.GetRegisterContext(), LLDB_INVALID_ADDRESS,224/*initial_value_ptr=*/nullptr,225/*object_address_ptr=*/nullptr);226if (!callee_addr_val) {227LLDB_LOG_ERROR(log, callee_addr_val.takeError(),228"IndirectCallEdge: Could not evaluate expression: {0}");229return nullptr;230}231232addr_t raw_addr =233callee_addr_val->GetScalar().ULongLong(LLDB_INVALID_ADDRESS);234if (raw_addr == LLDB_INVALID_ADDRESS) {235LLDB_LOG(log, "IndirectCallEdge: Could not extract address from scalar");236return nullptr;237}238239Address callee_addr;240if (!exe_ctx.GetTargetPtr()->ResolveLoadAddress(raw_addr, callee_addr)) {241LLDB_LOG(log, "IndirectCallEdge: Could not resolve callee's load address");242return nullptr;243}244245Function *f = callee_addr.CalculateSymbolContextFunction();246if (!f) {247LLDB_LOG(log, "IndirectCallEdge: Could not find complete function");248return nullptr;249}250251return f;252}253254/// @}255256//257Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid,258lldb::user_id_t type_uid, const Mangled &mangled, Type *type,259const AddressRange &range)260: UserID(func_uid), m_comp_unit(comp_unit), m_type_uid(type_uid),261m_type(type), m_mangled(mangled), m_block(func_uid), m_range(range),262m_frame_base(), m_flags(), m_prologue_byte_size(0) {263m_block.SetParentScope(this);264assert(comp_unit != nullptr);265}266267Function::~Function() = default;268269void Function::GetStartLineSourceInfo(FileSpec &source_file,270uint32_t &line_no) {271line_no = 0;272source_file.Clear();273274if (m_comp_unit == nullptr)275return;276277// Initialize m_type if it hasn't been initialized already278GetType();279280if (m_type != nullptr && m_type->GetDeclaration().GetLine() != 0) {281source_file = m_type->GetDeclaration().GetFile();282line_no = m_type->GetDeclaration().GetLine();283} else {284LineTable *line_table = m_comp_unit->GetLineTable();285if (line_table == nullptr)286return;287288LineEntry line_entry;289if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(),290line_entry, nullptr)) {291line_no = line_entry.line;292source_file = line_entry.GetFile();293}294}295}296297void Function::GetEndLineSourceInfo(FileSpec &source_file, uint32_t &line_no) {298line_no = 0;299source_file.Clear();300301// The -1 is kind of cheesy, but I want to get the last line entry for the302// given function, not the first entry of the next.303Address scratch_addr(GetAddressRange().GetBaseAddress());304scratch_addr.SetOffset(scratch_addr.GetOffset() +305GetAddressRange().GetByteSize() - 1);306307LineTable *line_table = m_comp_unit->GetLineTable();308if (line_table == nullptr)309return;310311LineEntry line_entry;312if (line_table->FindLineEntryByAddress(scratch_addr, line_entry, nullptr)) {313line_no = line_entry.line;314source_file = line_entry.GetFile();315}316}317318llvm::ArrayRef<std::unique_ptr<CallEdge>> Function::GetCallEdges() {319std::lock_guard<std::mutex> guard(m_call_edges_lock);320321if (m_call_edges_resolved)322return m_call_edges;323324Log *log = GetLog(LLDBLog::Step);325LLDB_LOG(log, "GetCallEdges: Attempting to parse call site info for {0}",326GetDisplayName());327328m_call_edges_resolved = true;329330// Find the SymbolFile which provided this function's definition.331Block &block = GetBlock(/*can_create*/true);332SymbolFile *sym_file = block.GetSymbolFile();333if (!sym_file)334return std::nullopt;335336// Lazily read call site information from the SymbolFile.337m_call_edges = sym_file->ParseCallEdgesInFunction(GetID());338339// Sort the call edges to speed up return_pc lookups.340llvm::sort(m_call_edges, [](const std::unique_ptr<CallEdge> &LHS,341const std::unique_ptr<CallEdge> &RHS) {342return LHS->GetSortKey() < RHS->GetSortKey();343});344345return m_call_edges;346}347348llvm::ArrayRef<std::unique_ptr<CallEdge>> Function::GetTailCallingEdges() {349// Tail calling edges are sorted at the end of the list. Find them by dropping350// all non-tail-calls.351return GetCallEdges().drop_until(352[](const std::unique_ptr<CallEdge> &edge) { return edge->IsTailCall(); });353}354355CallEdge *Function::GetCallEdgeForReturnAddress(addr_t return_pc,356Target &target) {357auto edges = GetCallEdges();358auto edge_it =359llvm::partition_point(edges, [&](const std::unique_ptr<CallEdge> &edge) {360return std::make_pair(edge->IsTailCall(),361edge->GetReturnPCAddress(*this, target)) <362std::make_pair(false, return_pc);363});364if (edge_it == edges.end() ||365edge_it->get()->GetReturnPCAddress(*this, target) != return_pc)366return nullptr;367return edge_it->get();368}369370Block &Function::GetBlock(bool can_create) {371if (!m_block.BlockInfoHasBeenParsed() && can_create) {372ModuleSP module_sp = CalculateSymbolContextModule();373if (module_sp) {374module_sp->GetSymbolFile()->ParseBlocksRecursive(*this);375} else {376Debugger::ReportError(llvm::formatv(377"unable to find module shared pointer for function '{0}' in {1}",378GetName().GetCString(), m_comp_unit->GetPrimaryFile().GetPath()));379}380m_block.SetBlockInfoHasBeenParsed(true, true);381}382return m_block;383}384385CompileUnit *Function::GetCompileUnit() { return m_comp_unit; }386387const CompileUnit *Function::GetCompileUnit() const { return m_comp_unit; }388389void Function::GetDescription(Stream *s, lldb::DescriptionLevel level,390Target *target) {391ConstString name = GetName();392ConstString mangled = m_mangled.GetMangledName();393394*s << "id = " << (const UserID &)*this;395if (name)396s->AsRawOstream() << ", name = \"" << name << '"';397if (mangled)398s->AsRawOstream() << ", mangled = \"" << mangled << '"';399if (level == eDescriptionLevelVerbose) {400*s << ", decl_context = {";401auto decl_context = GetCompilerContext();402// Drop the function itself from the context chain.403if (decl_context.size())404decl_context.pop_back();405llvm::interleaveComma(decl_context, *s, [&](auto &ctx) { ctx.Dump(*s); });406*s << "}";407}408*s << ", range = ";409Address::DumpStyle fallback_style;410if (level == eDescriptionLevelVerbose)411fallback_style = Address::DumpStyleModuleWithFileAddress;412else413fallback_style = Address::DumpStyleFileAddress;414GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress,415fallback_style);416}417418void Function::Dump(Stream *s, bool show_context) const {419s->Printf("%p: ", static_cast<const void *>(this));420s->Indent();421*s << "Function" << static_cast<const UserID &>(*this);422423m_mangled.Dump(s);424425if (m_type)426s->Printf(", type = %p", static_cast<void *>(m_type));427else if (m_type_uid != LLDB_INVALID_UID)428s->Printf(", type_uid = 0x%8.8" PRIx64, m_type_uid);429430s->EOL();431// Dump the root object432if (m_block.BlockInfoHasBeenParsed())433m_block.Dump(s, m_range.GetBaseAddress().GetFileAddress(), INT_MAX,434show_context);435}436437void Function::CalculateSymbolContext(SymbolContext *sc) {438sc->function = this;439m_comp_unit->CalculateSymbolContext(sc);440}441442ModuleSP Function::CalculateSymbolContextModule() {443SectionSP section_sp(m_range.GetBaseAddress().GetSection());444if (section_sp)445return section_sp->GetModule();446447return this->GetCompileUnit()->GetModule();448}449450CompileUnit *Function::CalculateSymbolContextCompileUnit() {451return this->GetCompileUnit();452}453454Function *Function::CalculateSymbolContextFunction() { return this; }455456lldb::DisassemblerSP Function::GetInstructions(const ExecutionContext &exe_ctx,457const char *flavor,458bool prefer_file_cache) {459ModuleSP module_sp(GetAddressRange().GetBaseAddress().GetModule());460if (module_sp && exe_ctx.HasTargetScope()) {461return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr,462flavor, exe_ctx.GetTargetRef(),463GetAddressRange(), !prefer_file_cache);464}465return lldb::DisassemblerSP();466}467468bool Function::GetDisassembly(const ExecutionContext &exe_ctx,469const char *flavor, Stream &strm,470bool prefer_file_cache) {471lldb::DisassemblerSP disassembler_sp =472GetInstructions(exe_ctx, flavor, prefer_file_cache);473if (disassembler_sp) {474const bool show_address = true;475const bool show_bytes = false;476const bool show_control_flow_kind = false;477disassembler_sp->GetInstructionList().Dump(478&strm, show_address, show_bytes, show_control_flow_kind, &exe_ctx);479return true;480}481return false;482}483484// Symbol *485// Function::CalculateSymbolContextSymbol ()486//{487// return // TODO: find the symbol for the function???488//}489490void Function::DumpSymbolContext(Stream *s) {491m_comp_unit->DumpSymbolContext(s);492s->Printf(", Function{0x%8.8" PRIx64 "}", GetID());493}494495size_t Function::MemorySize() const {496size_t mem_size = sizeof(Function) + m_block.MemorySize();497return mem_size;498}499500bool Function::GetIsOptimized() {501bool result = false;502503// Currently optimization is only indicted by the vendor extension504// DW_AT_APPLE_optimized which is set on a compile unit level.505if (m_comp_unit) {506result = m_comp_unit->GetIsOptimized();507}508return result;509}510511bool Function::IsTopLevelFunction() {512bool result = false;513514if (Language *language = Language::FindPlugin(GetLanguage()))515result = language->IsTopLevelFunction(*this);516517return result;518}519520ConstString Function::GetDisplayName() const {521return m_mangled.GetDisplayDemangledName();522}523524CompilerDeclContext Function::GetDeclContext() {525if (ModuleSP module_sp = CalculateSymbolContextModule())526if (SymbolFile *sym_file = module_sp->GetSymbolFile())527return sym_file->GetDeclContextForUID(GetID());528return {};529}530531std::vector<CompilerContext> Function::GetCompilerContext() {532if (ModuleSP module_sp = CalculateSymbolContextModule())533if (SymbolFile *sym_file = module_sp->GetSymbolFile())534return sym_file->GetCompilerContextForUID(GetID());535return {};536}537538Type *Function::GetType() {539if (m_type == nullptr) {540SymbolContext sc;541542CalculateSymbolContext(&sc);543544if (!sc.module_sp)545return nullptr;546547SymbolFile *sym_file = sc.module_sp->GetSymbolFile();548549if (sym_file == nullptr)550return nullptr;551552m_type = sym_file->ResolveTypeUID(m_type_uid);553}554return m_type;555}556557const Type *Function::GetType() const { return m_type; }558559CompilerType Function::GetCompilerType() {560Type *function_type = GetType();561if (function_type)562return function_type->GetFullCompilerType();563return CompilerType();564}565566uint32_t Function::GetPrologueByteSize() {567if (m_prologue_byte_size == 0 &&568m_flags.IsClear(flagsCalculatedPrologueSize)) {569m_flags.Set(flagsCalculatedPrologueSize);570LineTable *line_table = m_comp_unit->GetLineTable();571uint32_t prologue_end_line_idx = 0;572573if (line_table) {574LineEntry first_line_entry;575uint32_t first_line_entry_idx = UINT32_MAX;576if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(),577first_line_entry,578&first_line_entry_idx)) {579// Make sure the first line entry isn't already the end of the prologue580addr_t prologue_end_file_addr = LLDB_INVALID_ADDRESS;581addr_t line_zero_end_file_addr = LLDB_INVALID_ADDRESS;582583if (first_line_entry.is_prologue_end) {584prologue_end_file_addr =585first_line_entry.range.GetBaseAddress().GetFileAddress();586prologue_end_line_idx = first_line_entry_idx;587} else {588// Check the first few instructions and look for one that has589// is_prologue_end set to true.590const uint32_t last_line_entry_idx = first_line_entry_idx + 6;591for (uint32_t idx = first_line_entry_idx + 1;592idx < last_line_entry_idx; ++idx) {593LineEntry line_entry;594if (line_table->GetLineEntryAtIndex(idx, line_entry)) {595if (line_entry.is_prologue_end) {596prologue_end_file_addr =597line_entry.range.GetBaseAddress().GetFileAddress();598prologue_end_line_idx = idx;599break;600}601}602}603}604605// If we didn't find the end of the prologue in the line tables, then606// just use the end address of the first line table entry607if (prologue_end_file_addr == LLDB_INVALID_ADDRESS) {608// Check the first few instructions and look for one that has a line609// number that's different than the first entry.610uint32_t last_line_entry_idx = first_line_entry_idx + 6;611for (uint32_t idx = first_line_entry_idx + 1;612idx < last_line_entry_idx; ++idx) {613LineEntry line_entry;614if (line_table->GetLineEntryAtIndex(idx, line_entry)) {615if (line_entry.line != first_line_entry.line) {616prologue_end_file_addr =617line_entry.range.GetBaseAddress().GetFileAddress();618prologue_end_line_idx = idx;619break;620}621}622}623624if (prologue_end_file_addr == LLDB_INVALID_ADDRESS) {625prologue_end_file_addr =626first_line_entry.range.GetBaseAddress().GetFileAddress() +627first_line_entry.range.GetByteSize();628prologue_end_line_idx = first_line_entry_idx;629}630}631632const addr_t func_start_file_addr =633m_range.GetBaseAddress().GetFileAddress();634const addr_t func_end_file_addr =635func_start_file_addr + m_range.GetByteSize();636637// Now calculate the offset to pass the subsequent line 0 entries.638uint32_t first_non_zero_line = prologue_end_line_idx;639while (true) {640LineEntry line_entry;641if (line_table->GetLineEntryAtIndex(first_non_zero_line,642line_entry)) {643if (line_entry.line != 0)644break;645}646if (line_entry.range.GetBaseAddress().GetFileAddress() >=647func_end_file_addr)648break;649650first_non_zero_line++;651}652653if (first_non_zero_line > prologue_end_line_idx) {654LineEntry first_non_zero_entry;655if (line_table->GetLineEntryAtIndex(first_non_zero_line,656first_non_zero_entry)) {657line_zero_end_file_addr =658first_non_zero_entry.range.GetBaseAddress().GetFileAddress();659}660}661662// Verify that this prologue end file address in the function's address663// range just to be sure664if (func_start_file_addr < prologue_end_file_addr &&665prologue_end_file_addr < func_end_file_addr) {666m_prologue_byte_size = prologue_end_file_addr - func_start_file_addr;667}668669if (prologue_end_file_addr < line_zero_end_file_addr &&670line_zero_end_file_addr < func_end_file_addr) {671m_prologue_byte_size +=672line_zero_end_file_addr - prologue_end_file_addr;673}674}675}676}677678return m_prologue_byte_size;679}680681lldb::LanguageType Function::GetLanguage() const {682lldb::LanguageType lang = m_mangled.GuessLanguage();683if (lang != lldb::eLanguageTypeUnknown)684return lang;685686if (m_comp_unit)687return m_comp_unit->GetLanguage();688689return lldb::eLanguageTypeUnknown;690}691692ConstString Function::GetName() const {693return m_mangled.GetName();694}695696ConstString Function::GetNameNoArguments() const {697return m_mangled.GetName(Mangled::ePreferDemangledWithoutArguments);698}699700701