diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Core/Address.cpp')
-rw-r--r-- | contrib/llvm-project/lldb/source/Core/Address.cpp | 1055 |
1 files changed, 1055 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Core/Address.cpp b/contrib/llvm-project/lldb/source/Core/Address.cpp new file mode 100644 index 000000000000..5a4751bd5256 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Core/Address.cpp @@ -0,0 +1,1055 @@ +//===-- Address.cpp -------------------------------------------------------===// +// +// 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/Core/Address.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Declaration.h" +#include "lldb/Core/DumpDataExtractor.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/Section.h" +#include "lldb/Symbol/Block.h" +#include "lldb/Symbol/LineEntry.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Symbol/Symtab.h" +#include "lldb/Symbol/Type.h" +#include "lldb/Symbol/Variable.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/ABI.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/AnsiTerminal.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Status.h" +#include "lldb/Utility/Stream.h" +#include "lldb/Utility/StreamString.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include "llvm/TargetParser/Triple.h" + +#include <cstdint> +#include <memory> +#include <vector> + +#include <cassert> +#include <cinttypes> +#include <cstring> + +namespace lldb_private { +class CompileUnit; +} +namespace lldb_private { +class Function; +} + +using namespace lldb; +using namespace lldb_private; + +static size_t ReadBytes(ExecutionContextScope *exe_scope, + const Address &address, void *dst, size_t dst_len) { + if (exe_scope == nullptr) + return 0; + + TargetSP target_sp(exe_scope->CalculateTarget()); + if (target_sp) { + Status error; + bool force_live_memory = true; + return target_sp->ReadMemory(address, dst, dst_len, error, + force_live_memory); + } + return 0; +} + +static bool GetByteOrderAndAddressSize(ExecutionContextScope *exe_scope, + const Address &address, + ByteOrder &byte_order, + uint32_t &addr_size) { + byte_order = eByteOrderInvalid; + addr_size = 0; + if (exe_scope == nullptr) + return false; + + TargetSP target_sp(exe_scope->CalculateTarget()); + if (target_sp) { + byte_order = target_sp->GetArchitecture().GetByteOrder(); + addr_size = target_sp->GetArchitecture().GetAddressByteSize(); + } + + if (byte_order == eByteOrderInvalid || addr_size == 0) { + ModuleSP module_sp(address.GetModule()); + if (module_sp) { + byte_order = module_sp->GetArchitecture().GetByteOrder(); + addr_size = module_sp->GetArchitecture().GetAddressByteSize(); + } + } + return byte_order != eByteOrderInvalid && addr_size != 0; +} + +static uint64_t ReadUIntMax64(ExecutionContextScope *exe_scope, + const Address &address, uint32_t byte_size, + bool &success) { + uint64_t uval64 = 0; + if (exe_scope == nullptr || byte_size > sizeof(uint64_t)) { + success = false; + return 0; + } + uint64_t buf = 0; + + success = ReadBytes(exe_scope, address, &buf, byte_size) == byte_size; + if (success) { + ByteOrder byte_order = eByteOrderInvalid; + uint32_t addr_size = 0; + if (GetByteOrderAndAddressSize(exe_scope, address, byte_order, addr_size)) { + DataExtractor data(&buf, sizeof(buf), byte_order, addr_size); + lldb::offset_t offset = 0; + uval64 = data.GetU64(&offset); + } else + success = false; + } + return uval64; +} + +static bool ReadAddress(ExecutionContextScope *exe_scope, + const Address &address, uint32_t pointer_size, + Address &deref_so_addr) { + if (exe_scope == nullptr) + return false; + + bool success = false; + addr_t deref_addr = ReadUIntMax64(exe_scope, address, pointer_size, success); + if (success) { + ExecutionContext exe_ctx; + exe_scope->CalculateExecutionContext(exe_ctx); + // If we have any sections that are loaded, try and resolve using the + // section load list + Target *target = exe_ctx.GetTargetPtr(); + if (target && !target->GetSectionLoadList().IsEmpty()) { + if (target->GetSectionLoadList().ResolveLoadAddress(deref_addr, + deref_so_addr)) + return true; + } else { + // If we were not running, yet able to read an integer, we must have a + // module + ModuleSP module_sp(address.GetModule()); + + assert(module_sp); + if (module_sp->ResolveFileAddress(deref_addr, deref_so_addr)) + return true; + } + + // We couldn't make "deref_addr" into a section offset value, but we were + // able to read the address, so we return a section offset address with no + // section and "deref_addr" as the offset (address). + deref_so_addr.SetRawAddress(deref_addr); + return true; + } + return false; +} + +static bool DumpUInt(ExecutionContextScope *exe_scope, const Address &address, + uint32_t byte_size, Stream *strm) { + if (exe_scope == nullptr || byte_size == 0) + return false; + std::vector<uint8_t> buf(byte_size, 0); + + if (ReadBytes(exe_scope, address, &buf[0], buf.size()) == buf.size()) { + ByteOrder byte_order = eByteOrderInvalid; + uint32_t addr_size = 0; + if (GetByteOrderAndAddressSize(exe_scope, address, byte_order, addr_size)) { + DataExtractor data(&buf.front(), buf.size(), byte_order, addr_size); + + DumpDataExtractor(data, strm, + 0, // Start offset in "data" + eFormatHex, // Print as characters + buf.size(), // Size of item + 1, // Items count + UINT32_MAX, // num per line + LLDB_INVALID_ADDRESS, // base address + 0, // bitfield bit size + 0); // bitfield bit offset + + return true; + } + } + return false; +} + +static size_t ReadCStringFromMemory(ExecutionContextScope *exe_scope, + const Address &address, Stream *strm) { + if (exe_scope == nullptr) + return 0; + const size_t k_buf_len = 256; + char buf[k_buf_len + 1]; + buf[k_buf_len] = '\0'; // NULL terminate + + // Byte order and address size don't matter for C string dumping.. + DataExtractor data(buf, sizeof(buf), endian::InlHostByteOrder(), 4); + size_t total_len = 0; + size_t bytes_read; + Address curr_address(address); + strm->PutChar('"'); + while ((bytes_read = ReadBytes(exe_scope, curr_address, buf, k_buf_len)) > + 0) { + size_t len = strlen(buf); + if (len == 0) + break; + if (len > bytes_read) + len = bytes_read; + + DumpDataExtractor(data, strm, + 0, // Start offset in "data" + eFormatChar, // Print as characters + 1, // Size of item (1 byte for a char!) + len, // How many bytes to print? + UINT32_MAX, // num per line + LLDB_INVALID_ADDRESS, // base address + 0, // bitfield bit size + + 0); // bitfield bit offset + + total_len += bytes_read; + + if (len < k_buf_len) + break; + curr_address.SetOffset(curr_address.GetOffset() + bytes_read); + } + strm->PutChar('"'); + return total_len; +} + +Address::Address(lldb::addr_t abs_addr) : m_section_wp(), m_offset(abs_addr) {} + +Address::Address(addr_t address, const SectionList *section_list) + : m_section_wp() { + ResolveAddressUsingFileSections(address, section_list); +} + +const Address &Address::operator=(const Address &rhs) { + if (this != &rhs) { + m_section_wp = rhs.m_section_wp; + m_offset = rhs.m_offset; + } + return *this; +} + +bool Address::ResolveAddressUsingFileSections(addr_t file_addr, + const SectionList *section_list) { + if (section_list) { + SectionSP section_sp( + section_list->FindSectionContainingFileAddress(file_addr)); + m_section_wp = section_sp; + if (section_sp) { + assert(section_sp->ContainsFileAddress(file_addr)); + m_offset = file_addr - section_sp->GetFileAddress(); + return true; // Successfully transformed addr into a section offset + // address + } + } + m_offset = file_addr; + return false; // Failed to resolve this address to a section offset value +} + +/// if "addr_range_ptr" is not NULL, then fill in with the address range of the function. +bool Address::ResolveFunctionScope(SymbolContext &sym_ctx, + AddressRange *addr_range_ptr) { + constexpr SymbolContextItem resolve_scope = + eSymbolContextFunction | eSymbolContextSymbol; + + if (!(CalculateSymbolContext(&sym_ctx, resolve_scope) & resolve_scope)) { + if (addr_range_ptr) + addr_range_ptr->Clear(); + return false; + } + + if (!addr_range_ptr) + return true; + + return sym_ctx.GetAddressRange(resolve_scope, 0, false, *addr_range_ptr); +} + +ModuleSP Address::GetModule() const { + lldb::ModuleSP module_sp; + SectionSP section_sp(GetSection()); + if (section_sp) + module_sp = section_sp->GetModule(); + return module_sp; +} + +addr_t Address::GetFileAddress() const { + SectionSP section_sp(GetSection()); + if (section_sp) { + addr_t sect_file_addr = section_sp->GetFileAddress(); + if (sect_file_addr == LLDB_INVALID_ADDRESS) { + // Section isn't resolved, we can't return a valid file address + return LLDB_INVALID_ADDRESS; + } + // We have a valid file range, so we can return the file based address by + // adding the file base address to our offset + return sect_file_addr + m_offset; + } else if (SectionWasDeletedPrivate()) { + // Used to have a valid section but it got deleted so the offset doesn't + // mean anything without the section + return LLDB_INVALID_ADDRESS; + } + // No section, we just return the offset since it is the value in this case + return m_offset; +} + +addr_t Address::GetLoadAddress(Target *target) const { + SectionSP section_sp(GetSection()); + if (section_sp) { + if (target) { + addr_t sect_load_addr = section_sp->GetLoadBaseAddress(target); + + if (sect_load_addr != LLDB_INVALID_ADDRESS) { + // We have a valid file range, so we can return the file based address + // by adding the file base address to our offset + return sect_load_addr + m_offset; + } + } + } else if (SectionWasDeletedPrivate()) { + // Used to have a valid section but it got deleted so the offset doesn't + // mean anything without the section + return LLDB_INVALID_ADDRESS; + } else { + // We don't have a section so the offset is the load address + return m_offset; + } + // The section isn't resolved or an invalid target was passed in so we can't + // return a valid load address. + return LLDB_INVALID_ADDRESS; +} + +addr_t Address::GetCallableLoadAddress(Target *target, bool is_indirect) const { + addr_t code_addr = LLDB_INVALID_ADDRESS; + + if (is_indirect && target) { + ProcessSP processSP = target->GetProcessSP(); + Status error; + if (processSP) { + code_addr = processSP->ResolveIndirectFunction(this, error); + if (!error.Success()) + code_addr = LLDB_INVALID_ADDRESS; + } + } else { + code_addr = GetLoadAddress(target); + } + + if (code_addr == LLDB_INVALID_ADDRESS) + return code_addr; + + if (target) + return target->GetCallableLoadAddress(code_addr, GetAddressClass()); + return code_addr; +} + +bool Address::SetCallableLoadAddress(lldb::addr_t load_addr, Target *target) { + if (SetLoadAddress(load_addr, target)) { + if (target) + m_offset = target->GetCallableLoadAddress(m_offset, GetAddressClass()); + return true; + } + return false; +} + +addr_t Address::GetOpcodeLoadAddress(Target *target, + AddressClass addr_class) const { + addr_t code_addr = GetLoadAddress(target); + if (code_addr != LLDB_INVALID_ADDRESS) { + if (addr_class == AddressClass::eInvalid) + addr_class = GetAddressClass(); + code_addr = target->GetOpcodeLoadAddress(code_addr, addr_class); + } + return code_addr; +} + +bool Address::SetOpcodeLoadAddress(lldb::addr_t load_addr, Target *target, + AddressClass addr_class, + bool allow_section_end) { + if (SetLoadAddress(load_addr, target, allow_section_end)) { + if (target) { + if (addr_class == AddressClass::eInvalid) + addr_class = GetAddressClass(); + m_offset = target->GetOpcodeLoadAddress(m_offset, addr_class); + } + return true; + } + return false; +} + +bool Address::GetDescription(Stream &s, Target &target, + DescriptionLevel level) const { + assert(level == eDescriptionLevelBrief && + "Non-brief descriptions not implemented"); + LineEntry line_entry; + if (CalculateSymbolContextLineEntry(line_entry)) { + s.Printf(" (%s:%u:%u)", line_entry.GetFile().GetFilename().GetCString(), + line_entry.line, line_entry.column); + return true; + } + return false; +} + +bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, + DumpStyle fallback_style, uint32_t addr_size, + bool all_ranges, + std::optional<Stream::HighlightSettings> settings) const { + // If the section was nullptr, only load address is going to work unless we + // are trying to deref a pointer + SectionSP section_sp(GetSection()); + if (!section_sp && style != DumpStyleResolvedPointerDescription) + style = DumpStyleLoadAddress; + + ExecutionContext exe_ctx(exe_scope); + Target *target = exe_ctx.GetTargetPtr(); + // If addr_byte_size is UINT32_MAX, then determine the correct address byte + // size for the process or default to the size of addr_t + if (addr_size == UINT32_MAX) { + if (target) + addr_size = target->GetArchitecture().GetAddressByteSize(); + else + addr_size = sizeof(addr_t); + } + + Address so_addr; + switch (style) { + case DumpStyleInvalid: + return false; + + case DumpStyleSectionNameOffset: + if (section_sp) { + section_sp->DumpName(s->AsRawOstream()); + s->Printf(" + %" PRIu64, m_offset); + } else { + DumpAddress(s->AsRawOstream(), m_offset, addr_size); + } + break; + + case DumpStyleSectionPointerOffset: + s->Printf("(Section *)%p + ", static_cast<void *>(section_sp.get())); + DumpAddress(s->AsRawOstream(), m_offset, addr_size); + break; + + case DumpStyleModuleWithFileAddress: + if (section_sp) { + ModuleSP module_sp = section_sp->GetModule(); + if (module_sp) + s->Printf("%s[", module_sp->GetFileSpec().GetFilename().AsCString( + "<Unknown>")); + else + s->Printf("%s[", "<Unknown>"); + } + [[fallthrough]]; + case DumpStyleFileAddress: { + addr_t file_addr = GetFileAddress(); + if (file_addr == LLDB_INVALID_ADDRESS) { + if (fallback_style != DumpStyleInvalid) + return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); + return false; + } + DumpAddress(s->AsRawOstream(), file_addr, addr_size); + if (style == DumpStyleModuleWithFileAddress && section_sp) + s->PutChar(']'); + } break; + + case DumpStyleLoadAddress: { + addr_t load_addr = GetLoadAddress(target); + + /* + * MIPS: + * Display address in compressed form for MIPS16 or microMIPS + * if the address belongs to AddressClass::eCodeAlternateISA. + */ + if (target) { + const llvm::Triple::ArchType llvm_arch = + target->GetArchitecture().GetMachine(); + if (llvm_arch == llvm::Triple::mips || + llvm_arch == llvm::Triple::mipsel || + llvm_arch == llvm::Triple::mips64 || + llvm_arch == llvm::Triple::mips64el) + load_addr = GetCallableLoadAddress(target); + } + + if (load_addr == LLDB_INVALID_ADDRESS) { + if (fallback_style != DumpStyleInvalid) + return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); + return false; + } + DumpAddress(s->AsRawOstream(), load_addr, addr_size); + } break; + + case DumpStyleResolvedDescription: + case DumpStyleResolvedDescriptionNoModule: + case DumpStyleResolvedDescriptionNoFunctionArguments: + case DumpStyleNoFunctionName: + if (IsSectionOffset()) { + uint32_t pointer_size = 4; + ModuleSP module_sp(GetModule()); + if (target) + pointer_size = target->GetArchitecture().GetAddressByteSize(); + else if (module_sp) + pointer_size = module_sp->GetArchitecture().GetAddressByteSize(); + bool showed_info = false; + if (section_sp) { + SectionType sect_type = section_sp->GetType(); + switch (sect_type) { + case eSectionTypeData: + if (module_sp) { + if (Symtab *symtab = module_sp->GetSymtab()) { + const addr_t file_Addr = GetFileAddress(); + Symbol *symbol = + symtab->FindSymbolContainingFileAddress(file_Addr); + if (symbol) { + const char *symbol_name = symbol->GetName().AsCString(); + if (symbol_name) { + s->PutCStringColorHighlighted(symbol_name, settings); + addr_t delta = + file_Addr - symbol->GetAddressRef().GetFileAddress(); + if (delta) + s->Printf(" + %" PRIu64, delta); + showed_info = true; + } + } + } + } + break; + + case eSectionTypeDataCString: + // Read the C string from memory and display it + showed_info = true; + ReadCStringFromMemory(exe_scope, *this, s); + break; + + case eSectionTypeDataCStringPointers: + if (ReadAddress(exe_scope, *this, pointer_size, so_addr)) { +#if VERBOSE_OUTPUT + s->PutCString("(char *)"); + so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, + DumpStyleFileAddress); + s->PutCString(": "); +#endif + showed_info = true; + ReadCStringFromMemory(exe_scope, so_addr, s); + } + break; + + case eSectionTypeDataObjCMessageRefs: + if (ReadAddress(exe_scope, *this, pointer_size, so_addr)) { + if (target && so_addr.IsSectionOffset()) { + SymbolContext func_sc; + target->GetImages().ResolveSymbolContextForAddress( + so_addr, eSymbolContextEverything, func_sc); + if (func_sc.function != nullptr || func_sc.symbol != nullptr) { + showed_info = true; +#if VERBOSE_OUTPUT + s->PutCString("(objc_msgref *) -> { (func*)"); + so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, + DumpStyleFileAddress); +#else + s->PutCString("{ "); +#endif + Address cstr_addr(*this); + cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size); + func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, + false, true, true); + if (ReadAddress(exe_scope, cstr_addr, pointer_size, so_addr)) { +#if VERBOSE_OUTPUT + s->PutCString("), (char *)"); + so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, + DumpStyleFileAddress); + s->PutCString(" ("); +#else + s->PutCString(", "); +#endif + ReadCStringFromMemory(exe_scope, so_addr, s); + } +#if VERBOSE_OUTPUT + s->PutCString(") }"); +#else + s->PutCString(" }"); +#endif + } + } + } + break; + + case eSectionTypeDataObjCCFStrings: { + Address cfstring_data_addr(*this); + cfstring_data_addr.SetOffset(cfstring_data_addr.GetOffset() + + (2 * pointer_size)); + if (ReadAddress(exe_scope, cfstring_data_addr, pointer_size, + so_addr)) { +#if VERBOSE_OUTPUT + s->PutCString("(CFString *) "); + cfstring_data_addr.Dump(s, exe_scope, DumpStyleLoadAddress, + DumpStyleFileAddress); + s->PutCString(" -> @"); +#else + s->PutChar('@'); +#endif + if (so_addr.Dump(s, exe_scope, DumpStyleResolvedDescription)) + showed_info = true; + } + } break; + + case eSectionTypeData4: + // Read the 4 byte data and display it + showed_info = true; + s->PutCString("(uint32_t) "); + DumpUInt(exe_scope, *this, 4, s); + break; + + case eSectionTypeData8: + // Read the 8 byte data and display it + showed_info = true; + s->PutCString("(uint64_t) "); + DumpUInt(exe_scope, *this, 8, s); + break; + + case eSectionTypeData16: + // Read the 16 byte data and display it + showed_info = true; + s->PutCString("(uint128_t) "); + DumpUInt(exe_scope, *this, 16, s); + break; + + case eSectionTypeDataPointers: + // Read the pointer data and display it + if (ReadAddress(exe_scope, *this, pointer_size, so_addr)) { + s->PutCString("(void *)"); + so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, + DumpStyleFileAddress); + + showed_info = true; + if (so_addr.IsSectionOffset()) { + SymbolContext pointer_sc; + if (target) { + target->GetImages().ResolveSymbolContextForAddress( + so_addr, eSymbolContextEverything, pointer_sc); + if (pointer_sc.function != nullptr || + pointer_sc.symbol != nullptr) { + s->PutCString(": "); + pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, + false, true, true, false, + settings); + } + } + } + } + break; + + default: + break; + } + } + + if (!showed_info) { + if (module_sp) { + SymbolContext sc; + module_sp->ResolveSymbolContextForAddress( + *this, eSymbolContextEverything, sc); + if (sc.function || sc.symbol) { + bool show_stop_context = true; + const bool show_module = (style == DumpStyleResolvedDescription); + const bool show_fullpaths = false; + const bool show_inlined_frames = true; + const bool show_function_arguments = + (style != DumpStyleResolvedDescriptionNoFunctionArguments); + const bool show_function_name = (style != DumpStyleNoFunctionName); + if (sc.function == nullptr && sc.symbol != nullptr) { + // If we have just a symbol make sure it is in the right section + if (sc.symbol->ValueIsAddress()) { + if (sc.symbol->GetAddressRef().GetSection() != GetSection()) { + // don't show the module if the symbol is a trampoline symbol + show_stop_context = false; + } + } + } + if (show_stop_context) { + // We have a function or a symbol from the same sections as this + // address. + sc.DumpStopContext(s, exe_scope, *this, show_fullpaths, + show_module, show_inlined_frames, + show_function_arguments, show_function_name, + false, settings); + } else { + // We found a symbol but it was in a different section so it + // isn't the symbol we should be showing, just show the section + // name + offset + Dump(s, exe_scope, DumpStyleSectionNameOffset, DumpStyleInvalid, + UINT32_MAX, false, settings); + } + } + } + } + } else { + if (fallback_style != DumpStyleInvalid) + return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size, + false, settings); + return false; + } + break; + + case DumpStyleDetailedSymbolContext: + if (IsSectionOffset()) { + ModuleSP module_sp(GetModule()); + if (module_sp) { + SymbolContext sc; + module_sp->ResolveSymbolContextForAddress( + *this, eSymbolContextEverything | eSymbolContextVariable, sc); + if (sc.symbol) { + // If we have just a symbol make sure it is in the same section as + // our address. If it isn't, then we might have just found the last + // symbol that came before the address that we are looking up that + // has nothing to do with our address lookup. + if (sc.symbol->ValueIsAddress() && + sc.symbol->GetAddressRef().GetSection() != GetSection()) + sc.symbol = nullptr; + } + sc.GetDescription(s, eDescriptionLevelBrief, target, settings); + + if (sc.block) { + bool can_create = true; + bool get_parent_variables = true; + bool stop_if_block_is_inlined_function = false; + VariableList variable_list; + addr_t file_addr = GetFileAddress(); + sc.block->AppendVariables( + can_create, get_parent_variables, + stop_if_block_is_inlined_function, + [&](Variable *var) { + return var && var->LocationIsValidForAddress(*this); + }, + &variable_list); + ABISP abi = + ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture()); + for (const VariableSP &var_sp : variable_list) { + s->Indent(); + s->Printf(" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\"", + var_sp->GetID(), var_sp->GetName().GetCString()); + Type *type = var_sp->GetType(); + if (type) + s->Printf(", type = \"%s\"", type->GetName().GetCString()); + else + s->PutCString(", type = <unknown>"); + s->PutCString(", valid ranges = "); + if (var_sp->GetScopeRange().IsEmpty()) + s->PutCString("<block>"); + else if (all_ranges) { + for (auto range : var_sp->GetScopeRange()) + DumpAddressRange(s->AsRawOstream(), range.GetRangeBase(), + range.GetRangeEnd(), addr_size); + } else if (auto *range = + var_sp->GetScopeRange().FindEntryThatContains( + file_addr)) + DumpAddressRange(s->AsRawOstream(), range->GetRangeBase(), + range->GetRangeEnd(), addr_size); + s->PutCString(", location = "); + var_sp->DumpLocations(s, all_ranges ? LLDB_INVALID_ADDRESS : *this); + s->PutCString(", decl = "); + var_sp->GetDeclaration().DumpStopContext(s, false); + s->EOL(); + } + } + } + } else { + if (fallback_style != DumpStyleInvalid) + return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size, + false, settings); + return false; + } + break; + + case DumpStyleResolvedPointerDescription: { + Process *process = exe_ctx.GetProcessPtr(); + if (process) { + addr_t load_addr = GetLoadAddress(target); + if (load_addr != LLDB_INVALID_ADDRESS) { + Status memory_error; + addr_t dereferenced_load_addr = + process->ReadPointerFromMemory(load_addr, memory_error); + if (dereferenced_load_addr != LLDB_INVALID_ADDRESS) { + Address dereferenced_addr; + if (dereferenced_addr.SetLoadAddress(dereferenced_load_addr, + target)) { + StreamString strm; + if (dereferenced_addr.Dump(&strm, exe_scope, + DumpStyleResolvedDescription, + DumpStyleInvalid, addr_size)) { + DumpAddress(s->AsRawOstream(), dereferenced_load_addr, addr_size, + " -> ", " "); + s->Write(strm.GetString().data(), strm.GetSize()); + return true; + } + } + } + } + } + if (fallback_style != DumpStyleInvalid) + return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size); + return false; + } break; + } + + return true; +} + +bool Address::SectionWasDeleted() const { + if (GetSection()) + return false; + return SectionWasDeletedPrivate(); +} + +bool Address::SectionWasDeletedPrivate() const { + lldb::SectionWP empty_section_wp; + + // If either call to "std::weak_ptr::owner_before(...) value returns true, + // this indicates that m_section_wp once contained (possibly still does) a + // reference to a valid shared pointer. This helps us know if we had a valid + // reference to a section which is now invalid because the module it was in + // was unloaded/deleted, or if the address doesn't have a valid reference to + // a section. + return empty_section_wp.owner_before(m_section_wp) || + m_section_wp.owner_before(empty_section_wp); +} + +uint32_t +Address::CalculateSymbolContext(SymbolContext *sc, + SymbolContextItem resolve_scope) const { + sc->Clear(false); + // Absolute addresses don't have enough information to reconstruct even their + // target. + + SectionSP section_sp(GetSection()); + if (section_sp) { + ModuleSP module_sp(section_sp->GetModule()); + if (module_sp) { + sc->module_sp = module_sp; + if (sc->module_sp) + return sc->module_sp->ResolveSymbolContextForAddress( + *this, resolve_scope, *sc); + } + } + return 0; +} + +ModuleSP Address::CalculateSymbolContextModule() const { + SectionSP section_sp(GetSection()); + if (section_sp) + return section_sp->GetModule(); + return ModuleSP(); +} + +CompileUnit *Address::CalculateSymbolContextCompileUnit() const { + SectionSP section_sp(GetSection()); + if (section_sp) { + SymbolContext sc; + sc.module_sp = section_sp->GetModule(); + if (sc.module_sp) { + sc.module_sp->ResolveSymbolContextForAddress(*this, + eSymbolContextCompUnit, sc); + return sc.comp_unit; + } + } + return nullptr; +} + +Function *Address::CalculateSymbolContextFunction() const { + SectionSP section_sp(GetSection()); + if (section_sp) { + SymbolContext sc; + sc.module_sp = section_sp->GetModule(); + if (sc.module_sp) { + sc.module_sp->ResolveSymbolContextForAddress(*this, + eSymbolContextFunction, sc); + return sc.function; + } + } + return nullptr; +} + +Block *Address::CalculateSymbolContextBlock() const { + SectionSP section_sp(GetSection()); + if (section_sp) { + SymbolContext sc; + sc.module_sp = section_sp->GetModule(); + if (sc.module_sp) { + sc.module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextBlock, + sc); + return sc.block; + } + } + return nullptr; +} + +Symbol *Address::CalculateSymbolContextSymbol() const { + SectionSP section_sp(GetSection()); + if (section_sp) { + SymbolContext sc; + sc.module_sp = section_sp->GetModule(); + if (sc.module_sp) { + sc.module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextSymbol, + sc); + return sc.symbol; + } + } + return nullptr; +} + +bool Address::CalculateSymbolContextLineEntry(LineEntry &line_entry) const { + SectionSP section_sp(GetSection()); + if (section_sp) { + SymbolContext sc; + sc.module_sp = section_sp->GetModule(); + if (sc.module_sp) { + sc.module_sp->ResolveSymbolContextForAddress(*this, + eSymbolContextLineEntry, sc); + if (sc.line_entry.IsValid()) { + line_entry = sc.line_entry; + return true; + } + } + } + line_entry.Clear(); + return false; +} + +int Address::CompareFileAddress(const Address &a, const Address &b) { + addr_t a_file_addr = a.GetFileAddress(); + addr_t b_file_addr = b.GetFileAddress(); + if (a_file_addr < b_file_addr) + return -1; + if (a_file_addr > b_file_addr) + return +1; + return 0; +} + +int Address::CompareLoadAddress(const Address &a, const Address &b, + Target *target) { + assert(target != nullptr); + addr_t a_load_addr = a.GetLoadAddress(target); + addr_t b_load_addr = b.GetLoadAddress(target); + if (a_load_addr < b_load_addr) + return -1; + if (a_load_addr > b_load_addr) + return +1; + return 0; +} + +int Address::CompareModulePointerAndOffset(const Address &a, const Address &b) { + ModuleSP a_module_sp(a.GetModule()); + ModuleSP b_module_sp(b.GetModule()); + Module *a_module = a_module_sp.get(); + Module *b_module = b_module_sp.get(); + if (a_module < b_module) + return -1; + if (a_module > b_module) + return +1; + // Modules are the same, just compare the file address since they should be + // unique + addr_t a_file_addr = a.GetFileAddress(); + addr_t b_file_addr = b.GetFileAddress(); + if (a_file_addr < b_file_addr) + return -1; + if (a_file_addr > b_file_addr) + return +1; + return 0; +} + +size_t Address::MemorySize() const { + // Noting special for the memory size of a single Address object, it is just + // the size of itself. + return sizeof(Address); +} + +// NOTE: Be careful using this operator. It can correctly compare two +// addresses from the same Module correctly. It can't compare two addresses +// from different modules in any meaningful way, but it will compare the module +// pointers. +// +// To sum things up: +// - works great for addresses within the same module - it works for addresses +// across multiple modules, but don't expect the +// address results to make much sense +// +// This basically lets Address objects be used in ordered collection classes. + +bool lldb_private::operator<(const Address &lhs, const Address &rhs) { + ModuleSP lhs_module_sp(lhs.GetModule()); + ModuleSP rhs_module_sp(rhs.GetModule()); + Module *lhs_module = lhs_module_sp.get(); + Module *rhs_module = rhs_module_sp.get(); + if (lhs_module == rhs_module) { + // Addresses are in the same module, just compare the file addresses + return lhs.GetFileAddress() < rhs.GetFileAddress(); + } else { + // The addresses are from different modules, just use the module pointer + // value to get consistent ordering + return lhs_module < rhs_module; + } +} + +bool lldb_private::operator>(const Address &lhs, const Address &rhs) { + ModuleSP lhs_module_sp(lhs.GetModule()); + ModuleSP rhs_module_sp(rhs.GetModule()); + Module *lhs_module = lhs_module_sp.get(); + Module *rhs_module = rhs_module_sp.get(); + if (lhs_module == rhs_module) { + // Addresses are in the same module, just compare the file addresses + return lhs.GetFileAddress() > rhs.GetFileAddress(); + } else { + // The addresses are from different modules, just use the module pointer + // value to get consistent ordering + return lhs_module > rhs_module; + } +} + +// The operator == checks for exact equality only (same section, same offset) +bool lldb_private::operator==(const Address &a, const Address &rhs) { + return a.GetOffset() == rhs.GetOffset() && a.GetSection() == rhs.GetSection(); +} + +// The operator != checks for exact inequality only (differing section, or +// different offset) +bool lldb_private::operator!=(const Address &a, const Address &rhs) { + return a.GetOffset() != rhs.GetOffset() || a.GetSection() != rhs.GetSection(); +} + +AddressClass Address::GetAddressClass() const { + ModuleSP module_sp(GetModule()); + if (module_sp) { + ObjectFile *obj_file = module_sp->GetObjectFile(); + if (obj_file) { + // Give the symbol file a chance to add to the unified section list + // and to the symtab. + module_sp->GetSymtab(); + return obj_file->GetAddressClass(GetFileAddress()); + } + } + return AddressClass::eUnknown; +} + +bool Address::SetLoadAddress(lldb::addr_t load_addr, Target *target, + bool allow_section_end) { + if (target && target->GetSectionLoadList().ResolveLoadAddress( + load_addr, *this, allow_section_end)) + return true; + m_section_wp.reset(); + m_offset = load_addr; + return false; +} |