Files
linux-packaging-mono/external/llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
Pat Tullmann 0cb742dafb binfmt-detector-cli: rewrite to support PE32+ binaries (#38)
Rewrite with hard-coded offsets into the PE file format to discern
if a binary is PE32 or PE32+, and then to determine if it contains
a "CLR Data Directory" entry that looks valid.

Tested with PE32 and PE32+ compiled Mono binaries, PE32 and PE32+ native
binaries, and a random assortment of garbage files.

Former-commit-id: 9e7ac86ec84f653a2f79b87183efd5b0ebda001b
2023-10-16 20:16:47 +02:00

4370 lines
159 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- SymbolFileDWARF.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "SymbolFileDWARF.h"
// Other libraries and framework includes
#include "llvm/Support/Casting.h"
#include "llvm/Support/Threading.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/Value.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Interpreter/OptionValueFileSpecList.h"
#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangUtil.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/CompilerDecl.h"
#include "lldb/Symbol/CompilerDeclContext.h"
#include "lldb/Symbol/DebugMacros.h"
#include "lldb/Symbol/LineTable.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/TypeMap.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/VariableList.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Target/Language.h"
#include "lldb/Host/TaskPool.h"
#include "DWARFASTParser.h"
#include "DWARFASTParserClang.h"
#include "DWARFCompileUnit.h"
#include "DWARFDIECollection.h"
#include "DWARFDebugAbbrev.h"
#include "DWARFDebugAranges.h"
#include "DWARFDebugInfo.h"
#include "DWARFDebugLine.h"
#include "DWARFDebugMacro.h"
#include "DWARFDebugPubnames.h"
#include "DWARFDebugRanges.h"
#include "DWARFDeclContext.h"
#include "DWARFFormValue.h"
#include "LogChannelDWARF.h"
#include "SymbolFileDWARFDebugMap.h"
#include "SymbolFileDWARFDwo.h"
#include "SymbolFileDWARFDwp.h"
#include "llvm/Support/FileSystem.h"
#include <map>
#include <ctype.h>
#include <string.h>
//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
#ifdef ENABLE_DEBUG_PRINTF
#include <stdio.h>
#define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
#else
#define DEBUG_PRINTF(fmt, ...)
#endif
using namespace lldb;
using namespace lldb_private;
// static inline bool
// child_requires_parent_class_union_or_struct_to_be_completed (dw_tag_t tag)
//{
// switch (tag)
// {
// default:
// break;
// case DW_TAG_subprogram:
// case DW_TAG_inlined_subroutine:
// case DW_TAG_class_type:
// case DW_TAG_structure_type:
// case DW_TAG_union_type:
// return true;
// }
// return false;
//}
//
namespace {
PropertyDefinition g_properties[] = {
{"comp-dir-symlink-paths", OptionValue::eTypeFileSpecList, true, 0, nullptr,
nullptr, "If the DW_AT_comp_dir matches any of these paths the symbolic "
"links will be resolved at DWARF parse time."},
{nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}};
enum { ePropertySymLinkPaths };
class PluginProperties : public Properties {
public:
static ConstString GetSettingName() {
return SymbolFileDWARF::GetPluginNameStatic();
}
PluginProperties() {
m_collection_sp.reset(new OptionValueProperties(GetSettingName()));
m_collection_sp->Initialize(g_properties);
}
FileSpecList &GetSymLinkPaths() {
OptionValueFileSpecList *option_value =
m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(
nullptr, true, ePropertySymLinkPaths);
assert(option_value);
return option_value->GetCurrentValue();
}
};
typedef std::shared_ptr<PluginProperties> SymbolFileDWARFPropertiesSP;
static const SymbolFileDWARFPropertiesSP &GetGlobalPluginProperties() {
static const auto g_settings_sp(std::make_shared<PluginProperties>());
return g_settings_sp;
}
} // anonymous namespace end
static const char *removeHostnameFromPathname(const char *path_from_dwarf) {
if (!path_from_dwarf || !path_from_dwarf[0]) {
return path_from_dwarf;
}
const char *colon_pos = strchr(path_from_dwarf, ':');
if (nullptr == colon_pos) {
return path_from_dwarf;
}
const char *slash_pos = strchr(path_from_dwarf, '/');
if (slash_pos && (slash_pos < colon_pos)) {
return path_from_dwarf;
}
// check whether we have a windows path, and so the first character
// is a drive-letter not a hostname.
if (colon_pos == path_from_dwarf + 1 && isalpha(*path_from_dwarf) &&
strlen(path_from_dwarf) > 2 && '\\' == path_from_dwarf[2]) {
return path_from_dwarf;
}
return colon_pos + 1;
}
static const char *resolveCompDir(const char *path_from_dwarf) {
if (!path_from_dwarf)
return nullptr;
// DWARF2/3 suggests the form hostname:pathname for compilation directory.
// Remove the host part if present.
const char *local_path = removeHostnameFromPathname(path_from_dwarf);
if (!local_path)
return nullptr;
bool is_symlink = false;
FileSpec local_path_spec(local_path, false);
const auto &file_specs = GetGlobalPluginProperties()->GetSymLinkPaths();
for (size_t i = 0; i < file_specs.GetSize() && !is_symlink; ++i)
is_symlink = FileSpec::Equal(file_specs.GetFileSpecAtIndex(i),
local_path_spec, true);
if (!is_symlink)
return local_path;
namespace fs = llvm::sys::fs;
if (fs::get_file_type(local_path_spec.GetPath(), false) !=
fs::file_type::symlink_file)
return local_path;
FileSpec resolved_local_path_spec;
const auto error =
FileSystem::Readlink(local_path_spec, resolved_local_path_spec);
if (error.Success())
return resolved_local_path_spec.GetCString();
return nullptr;
}
DWARFCompileUnit *SymbolFileDWARF::GetBaseCompileUnit() {
return nullptr;
}
void SymbolFileDWARF::Initialize() {
LogChannelDWARF::Initialize();
PluginManager::RegisterPlugin(GetPluginNameStatic(),
GetPluginDescriptionStatic(), CreateInstance,
DebuggerInitialize);
}
void SymbolFileDWARF::DebuggerInitialize(Debugger &debugger) {
if (!PluginManager::GetSettingForSymbolFilePlugin(
debugger, PluginProperties::GetSettingName())) {
const bool is_global_setting = true;
PluginManager::CreateSettingForSymbolFilePlugin(
debugger, GetGlobalPluginProperties()->GetValueProperties(),
ConstString("Properties for the dwarf symbol-file plug-in."),
is_global_setting);
}
}
void SymbolFileDWARF::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
LogChannelDWARF::Terminate();
}
lldb_private::ConstString SymbolFileDWARF::GetPluginNameStatic() {
static ConstString g_name("dwarf");
return g_name;
}
const char *SymbolFileDWARF::GetPluginDescriptionStatic() {
return "DWARF and DWARF3 debug symbol file reader.";
}
SymbolFile *SymbolFileDWARF::CreateInstance(ObjectFile *obj_file) {
return new SymbolFileDWARF(obj_file);
}
TypeList *SymbolFileDWARF::GetTypeList() {
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (debug_map_symfile)
return debug_map_symfile->GetTypeList();
else
return m_obj_file->GetModule()->GetTypeList();
}
void SymbolFileDWARF::GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset,
dw_offset_t max_die_offset, uint32_t type_mask,
TypeSet &type_set) {
if (die) {
const dw_offset_t die_offset = die.GetOffset();
if (die_offset >= max_die_offset)
return;
if (die_offset >= min_die_offset) {
const dw_tag_t tag = die.Tag();
bool add_type = false;
switch (tag) {
case DW_TAG_array_type:
add_type = (type_mask & eTypeClassArray) != 0;
break;
case DW_TAG_unspecified_type:
case DW_TAG_base_type:
add_type = (type_mask & eTypeClassBuiltin) != 0;
break;
case DW_TAG_class_type:
add_type = (type_mask & eTypeClassClass) != 0;
break;
case DW_TAG_structure_type:
add_type = (type_mask & eTypeClassStruct) != 0;
break;
case DW_TAG_union_type:
add_type = (type_mask & eTypeClassUnion) != 0;
break;
case DW_TAG_enumeration_type:
add_type = (type_mask & eTypeClassEnumeration) != 0;
break;
case DW_TAG_subroutine_type:
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
add_type = (type_mask & eTypeClassFunction) != 0;
break;
case DW_TAG_pointer_type:
add_type = (type_mask & eTypeClassPointer) != 0;
break;
case DW_TAG_rvalue_reference_type:
case DW_TAG_reference_type:
add_type = (type_mask & eTypeClassReference) != 0;
break;
case DW_TAG_typedef:
add_type = (type_mask & eTypeClassTypedef) != 0;
break;
case DW_TAG_ptr_to_member_type:
add_type = (type_mask & eTypeClassMemberPointer) != 0;
break;
}
if (add_type) {
const bool assert_not_being_parsed = true;
Type *type = ResolveTypeUID(die, assert_not_being_parsed);
if (type) {
if (type_set.find(type) == type_set.end())
type_set.insert(type);
}
}
}
for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid();
child_die = child_die.GetSibling()) {
GetTypes(child_die, min_die_offset, max_die_offset, type_mask, type_set);
}
}
}
size_t SymbolFileDWARF::GetTypes(SymbolContextScope *sc_scope,
uint32_t type_mask, TypeList &type_list)
{
TypeSet type_set;
CompileUnit *comp_unit = NULL;
DWARFCompileUnit *dwarf_cu = NULL;
if (sc_scope)
comp_unit = sc_scope->CalculateSymbolContextCompileUnit();
if (comp_unit) {
dwarf_cu = GetDWARFCompileUnit(comp_unit);
if (dwarf_cu == 0)
return 0;
GetTypes(dwarf_cu->DIE(), dwarf_cu->GetOffset(),
dwarf_cu->GetNextCompileUnitOffset(), type_mask, type_set);
} else {
DWARFDebugInfo *info = DebugInfo();
if (info) {
const size_t num_cus = info->GetNumCompileUnits();
for (size_t cu_idx = 0; cu_idx < num_cus; ++cu_idx) {
dwarf_cu = info->GetCompileUnitAtIndex(cu_idx);
if (dwarf_cu) {
GetTypes(dwarf_cu->DIE(), 0, UINT32_MAX, type_mask, type_set);
}
}
}
}
std::set<CompilerType> compiler_type_set;
size_t num_types_added = 0;
for (Type *type : type_set) {
CompilerType compiler_type = type->GetForwardCompilerType();
if (compiler_type_set.find(compiler_type) == compiler_type_set.end()) {
compiler_type_set.insert(compiler_type);
type_list.Insert(type->shared_from_this());
++num_types_added;
}
}
return num_types_added;
}
//----------------------------------------------------------------------
// Gets the first parent that is a lexical block, function or inlined
// subroutine, or compile unit.
//----------------------------------------------------------------------
DWARFDIE
SymbolFileDWARF::GetParentSymbolContextDIE(const DWARFDIE &child_die) {
DWARFDIE die;
for (die = child_die.GetParent(); die; die = die.GetParent()) {
dw_tag_t tag = die.Tag();
switch (tag) {
case DW_TAG_compile_unit:
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_lexical_block:
return die;
}
}
return DWARFDIE();
}
SymbolFileDWARF::SymbolFileDWARF(ObjectFile *objfile)
: SymbolFile(objfile), UserID(0), // Used by SymbolFileDWARFDebugMap to when
// this class parses .o files to contain
// the .o file index/ID
m_debug_map_module_wp(), m_debug_map_symfile(NULL), m_data_debug_abbrev(),
m_data_debug_aranges(), m_data_debug_frame(), m_data_debug_info(),
m_data_debug_line(), m_data_debug_macro(), m_data_debug_loc(),
m_data_debug_ranges(), m_data_debug_str(), m_data_apple_names(),
m_data_apple_types(), m_data_apple_namespaces(), m_abbr(), m_info(),
m_line(), m_apple_names_ap(), m_apple_types_ap(), m_apple_namespaces_ap(),
m_apple_objc_ap(), m_function_basename_index(),
m_function_fullname_index(), m_function_method_index(),
m_function_selector_index(), m_objc_class_selectors_index(),
m_global_index(), m_type_index(), m_namespace_index(), m_indexed(false),
m_using_apple_tables(false), m_fetched_external_modules(false),
m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate), m_ranges(),
m_unique_ast_type_map() {}
SymbolFileDWARF::~SymbolFileDWARF() {}
static const ConstString &GetDWARFMachOSegmentName() {
static ConstString g_dwarf_section_name("__DWARF");
return g_dwarf_section_name;
}
UniqueDWARFASTTypeMap &SymbolFileDWARF::GetUniqueDWARFASTTypeMap() {
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (debug_map_symfile)
return debug_map_symfile->GetUniqueDWARFASTTypeMap();
else
return m_unique_ast_type_map;
}
TypeSystem *SymbolFileDWARF::GetTypeSystemForLanguage(LanguageType language) {
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
TypeSystem *type_system;
if (debug_map_symfile) {
type_system = debug_map_symfile->GetTypeSystemForLanguage(language);
} else {
type_system = m_obj_file->GetModule()->GetTypeSystemForLanguage(language);
if (type_system)
type_system->SetSymbolFile(this);
}
return type_system;
}
void SymbolFileDWARF::InitializeObject() {
ModuleSP module_sp(m_obj_file->GetModule());
if (module_sp) {
const SectionList *section_list = module_sp->GetSectionList();
Section *section =
section_list->FindSectionByName(GetDWARFMachOSegmentName()).get();
if (section)
m_obj_file->ReadSectionData(section, m_dwarf_data);
}
get_apple_names_data();
if (m_data_apple_names.m_data.GetByteSize() > 0) {
m_apple_names_ap.reset(new DWARFMappedHash::MemoryTable(
m_data_apple_names.m_data, get_debug_str_data(), ".apple_names"));
if (m_apple_names_ap->IsValid())
m_using_apple_tables = true;
else
m_apple_names_ap.reset();
}
get_apple_types_data();
if (m_data_apple_types.m_data.GetByteSize() > 0) {
m_apple_types_ap.reset(new DWARFMappedHash::MemoryTable(
m_data_apple_types.m_data, get_debug_str_data(), ".apple_types"));
if (m_apple_types_ap->IsValid())
m_using_apple_tables = true;
else
m_apple_types_ap.reset();
}
get_apple_namespaces_data();
if (m_data_apple_namespaces.m_data.GetByteSize() > 0) {
m_apple_namespaces_ap.reset(new DWARFMappedHash::MemoryTable(
m_data_apple_namespaces.m_data, get_debug_str_data(),
".apple_namespaces"));
if (m_apple_namespaces_ap->IsValid())
m_using_apple_tables = true;
else
m_apple_namespaces_ap.reset();
}
get_apple_objc_data();
if (m_data_apple_objc.m_data.GetByteSize() > 0) {
m_apple_objc_ap.reset(new DWARFMappedHash::MemoryTable(
m_data_apple_objc.m_data, get_debug_str_data(), ".apple_objc"));
if (m_apple_objc_ap->IsValid())
m_using_apple_tables = true;
else
m_apple_objc_ap.reset();
}
}
bool SymbolFileDWARF::SupportedVersion(uint16_t version) {
return version == 2 || version == 3 || version == 4;
}
uint32_t SymbolFileDWARF::CalculateAbilities() {
uint32_t abilities = 0;
if (m_obj_file != NULL) {
const Section *section = NULL;
const SectionList *section_list = m_obj_file->GetSectionList();
if (section_list == NULL)
return 0;
// On non Apple platforms we might have .debug_types debug info that
// is created by using "-fdebug-types-section". LLDB currently will try
// to load this debug info, but it causes crashes during debugging when
// types are missing since it doesn't know how to parse the info in
// the .debug_types type units. This causes all complex debug info
// types to be unresolved. Because this causes LLDB to crash and since
// it really doesn't provide a solid debuggiung experience, we should
// disable trying to debug this kind of DWARF until support gets
// added or deprecated.
if (section_list->FindSectionByName(ConstString(".debug_types"))) {
m_obj_file->GetModule()->ReportWarning(
"lldb doesn’t support .debug_types debug info");
return 0;
}
uint64_t debug_abbrev_file_size = 0;
uint64_t debug_info_file_size = 0;
uint64_t debug_line_file_size = 0;
section = section_list->FindSectionByName(GetDWARFMachOSegmentName()).get();
if (section)
section_list = &section->GetChildren();
section =
section_list->FindSectionByType(eSectionTypeDWARFDebugInfo, true).get();
if (section != NULL) {
debug_info_file_size = section->GetFileSize();
section =
section_list->FindSectionByType(eSectionTypeDWARFDebugAbbrev, true)
.get();
if (section)
debug_abbrev_file_size = section->GetFileSize();
DWARFDebugAbbrev *abbrev = DebugAbbrev();
if (abbrev) {
std::set<dw_form_t> invalid_forms;
abbrev->GetUnsupportedForms(invalid_forms);
if (!invalid_forms.empty()) {
StreamString error;
error.Printf("unsupported DW_FORM value%s:", invalid_forms.size() > 1 ? "s" : "");
for (auto form : invalid_forms)
error.Printf(" %#x", form);
m_obj_file->GetModule()->ReportWarning("%s", error.GetString().str().c_str());
return 0;
}
}
section =
section_list->FindSectionByType(eSectionTypeDWARFDebugLine, true)
.get();
if (section)
debug_line_file_size = section->GetFileSize();
} else {
const char *symfile_dir_cstr =
m_obj_file->GetFileSpec().GetDirectory().GetCString();
if (symfile_dir_cstr) {
if (strcasestr(symfile_dir_cstr, ".dsym")) {
if (m_obj_file->GetType() == ObjectFile::eTypeDebugInfo) {
// We have a dSYM file that didn't have a any debug info.
// If the string table has a size of 1, then it was made from
// an executable with no debug info, or from an executable that
// was stripped.
section =
section_list->FindSectionByType(eSectionTypeDWARFDebugStr, true)
.get();
if (section && section->GetFileSize() == 1) {
m_obj_file->GetModule()->ReportWarning(
"empty dSYM file detected, dSYM was created with an "
"executable with no debug info.");
}
}
}
}
}
if (debug_abbrev_file_size > 0 && debug_info_file_size > 0)
abilities |= CompileUnits | Functions | Blocks | GlobalVariables |
LocalVariables | VariableTypes;
if (debug_line_file_size > 0)
abilities |= LineTables;
}
return abilities;
}
const DWARFDataExtractor &
SymbolFileDWARF::GetCachedSectionData(lldb::SectionType sect_type,
DWARFDataSegment &data_segment) {
llvm::call_once(data_segment.m_flag, [this, sect_type, &data_segment] {
this->LoadSectionData(sect_type, std::ref(data_segment.m_data));
});
return data_segment.m_data;
}
void SymbolFileDWARF::LoadSectionData(lldb::SectionType sect_type,
DWARFDataExtractor &data) {
ModuleSP module_sp(m_obj_file->GetModule());
const SectionList *section_list = module_sp->GetSectionList();
if (section_list) {
SectionSP section_sp(section_list->FindSectionByType(sect_type, true));
if (section_sp) {
// See if we memory mapped the DWARF segment?
if (m_dwarf_data.GetByteSize()) {
data.SetData(m_dwarf_data, section_sp->GetOffset(),
section_sp->GetFileSize());
} else {
if (m_obj_file->ReadSectionData(section_sp.get(), data) == 0)
data.Clear();
}
}
}
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_abbrev_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugAbbrev,
m_data_debug_abbrev);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_addr_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugAddr, m_data_debug_addr);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_aranges_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugAranges,
m_data_debug_aranges);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_frame_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugFrame, m_data_debug_frame);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_info_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugInfo, m_data_debug_info);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_line_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugLine, m_data_debug_line);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_macro_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugMacro, m_data_debug_macro);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_loc_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugLoc, m_data_debug_loc);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_ranges_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugRanges,
m_data_debug_ranges);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_str_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugStr, m_data_debug_str);
}
const DWARFDataExtractor &SymbolFileDWARF::get_debug_str_offsets_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugStrOffsets,
m_data_debug_str_offsets);
}
const DWARFDataExtractor &SymbolFileDWARF::get_apple_names_data() {
return GetCachedSectionData(eSectionTypeDWARFAppleNames, m_data_apple_names);
}
const DWARFDataExtractor &SymbolFileDWARF::get_apple_types_data() {
return GetCachedSectionData(eSectionTypeDWARFAppleTypes, m_data_apple_types);
}
const DWARFDataExtractor &SymbolFileDWARF::get_apple_namespaces_data() {
return GetCachedSectionData(eSectionTypeDWARFAppleNamespaces,
m_data_apple_namespaces);
}
const DWARFDataExtractor &SymbolFileDWARF::get_apple_objc_data() {
return GetCachedSectionData(eSectionTypeDWARFAppleObjC, m_data_apple_objc);
}
DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() {
if (m_abbr.get() == NULL) {
const DWARFDataExtractor &debug_abbrev_data = get_debug_abbrev_data();
if (debug_abbrev_data.GetByteSize() > 0) {
m_abbr.reset(new DWARFDebugAbbrev());
if (m_abbr.get())
m_abbr->Parse(debug_abbrev_data);
}
}
return m_abbr.get();
}
const DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() const {
return m_abbr.get();
}
DWARFDebugInfo *SymbolFileDWARF::DebugInfo() {
if (m_info.get() == NULL) {
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION,
static_cast<void *>(this));
if (get_debug_info_data().GetByteSize() > 0) {
m_info.reset(new DWARFDebugInfo());
if (m_info.get()) {
m_info->SetDwarfData(this);
}
}
}
return m_info.get();
}
const DWARFDebugInfo *SymbolFileDWARF::DebugInfo() const {
return m_info.get();
}
DWARFCompileUnit *
SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) {
if (!comp_unit)
return nullptr;
DWARFDebugInfo *info = DebugInfo();
if (info) {
// Just a normal DWARF file whose user ID for the compile unit is
// the DWARF offset itself
DWARFCompileUnit *dwarf_cu =
info->GetCompileUnit((dw_offset_t)comp_unit->GetID());
if (dwarf_cu && dwarf_cu->GetUserData() == NULL)
dwarf_cu->SetUserData(comp_unit);
return dwarf_cu;
}
return NULL;
}
DWARFDebugRanges *SymbolFileDWARF::DebugRanges() {
if (m_ranges.get() == NULL) {
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION,
static_cast<void *>(this));
if (get_debug_ranges_data().GetByteSize() > 0) {
m_ranges.reset(new DWARFDebugRanges());
if (m_ranges.get())
m_ranges->Extract(this);
}
}
return m_ranges.get();
}
const DWARFDebugRanges *SymbolFileDWARF::DebugRanges() const {
return m_ranges.get();
}
lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit *dwarf_cu,
uint32_t cu_idx) {
CompUnitSP cu_sp;
if (dwarf_cu) {
CompileUnit *comp_unit = (CompileUnit *)dwarf_cu->GetUserData();
if (comp_unit) {
// We already parsed this compile unit, had out a shared pointer to it
cu_sp = comp_unit->shared_from_this();
} else {
if (dwarf_cu->GetSymbolFileDWARF() != this) {
return dwarf_cu->GetSymbolFileDWARF()->ParseCompileUnit(dwarf_cu,
cu_idx);
} else if (dwarf_cu->GetOffset() == 0 && GetDebugMapSymfile()) {
// Let the debug map create the compile unit
cu_sp = m_debug_map_symfile->GetCompileUnit(this);
dwarf_cu->SetUserData(cu_sp.get());
} else {
ModuleSP module_sp(m_obj_file->GetModule());
if (module_sp) {
const DWARFDIE cu_die = dwarf_cu->GetCompileUnitDIEOnly();
if (cu_die) {
FileSpec cu_file_spec{cu_die.GetName(), false};
if (cu_file_spec) {
// If we have a full path to the compile unit, we don't need to
// resolve
// the file. This can be expensive e.g. when the source files are
// NFS mounted.
if (cu_file_spec.IsRelative()) {
const char *cu_comp_dir{
cu_die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr)};
cu_file_spec.PrependPathComponent(resolveCompDir(cu_comp_dir));
}
std::string remapped_file;
if (module_sp->RemapSourceFile(cu_file_spec.GetPath(),
remapped_file))
cu_file_spec.SetFile(remapped_file, false);
}
LanguageType cu_language = DWARFCompileUnit::LanguageTypeFromDWARF(
cu_die.GetAttributeValueAsUnsigned(DW_AT_language, 0));
bool is_optimized = dwarf_cu->GetIsOptimized();
cu_sp.reset(new CompileUnit(
module_sp, dwarf_cu, cu_file_spec, dwarf_cu->GetID(),
cu_language, is_optimized ? eLazyBoolYes : eLazyBoolNo));
if (cu_sp) {
// If we just created a compile unit with an invalid file spec,
// try and get the
// first entry in the supports files from the line table as that
// should be the
// compile unit.
if (!cu_file_spec) {
cu_file_spec = cu_sp->GetSupportFiles().GetFileSpecAtIndex(1);
if (cu_file_spec) {
(FileSpec &)(*cu_sp) = cu_file_spec;
// Also fix the invalid file spec which was copied from the
// compile unit.
cu_sp->GetSupportFiles().Replace(0, cu_file_spec);
}
}
dwarf_cu->SetUserData(cu_sp.get());
// Figure out the compile unit index if we weren't given one
if (cu_idx == UINT32_MAX)
DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx);
m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(
cu_idx, cu_sp);
}
}
}
}
}
}
return cu_sp;
}
uint32_t SymbolFileDWARF::GetNumCompileUnits() {
DWARFDebugInfo *info = DebugInfo();
if (info)
return info->GetNumCompileUnits();
return 0;
}
CompUnitSP SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx) {
CompUnitSP cu_sp;
DWARFDebugInfo *info = DebugInfo();
if (info) {
DWARFCompileUnit *dwarf_cu = info->GetCompileUnitAtIndex(cu_idx);
if (dwarf_cu)
cu_sp = ParseCompileUnit(dwarf_cu, cu_idx);
}
return cu_sp;
}
Function *SymbolFileDWARF::ParseCompileUnitFunction(const SymbolContext &sc,
const DWARFDIE &die) {
if (die.IsValid()) {
TypeSystem *type_system =
GetTypeSystemForLanguage(die.GetCU()->GetLanguageType());
if (type_system) {
DWARFASTParser *dwarf_ast = type_system->GetDWARFParser();
if (dwarf_ast)
return dwarf_ast->ParseFunctionFromDWARF(sc, die);
}
}
return nullptr;
}
bool SymbolFileDWARF::FixupAddress(Address &addr) {
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (debug_map_symfile) {
return debug_map_symfile->LinkOSOAddress(addr);
}
// This is a normal DWARF file, no address fixups need to happen
return true;
}
lldb::LanguageType
SymbolFileDWARF::ParseCompileUnitLanguage(const SymbolContext &sc) {
assert(sc.comp_unit);
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu)
return dwarf_cu->GetLanguageType();
else
return eLanguageTypeUnknown;
}
size_t SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc) {
assert(sc.comp_unit);
size_t functions_added = 0;
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu) {
DWARFDIECollection function_dies;
const size_t num_functions =
dwarf_cu->AppendDIEsWithTag(DW_TAG_subprogram, function_dies);
size_t func_idx;
for (func_idx = 0; func_idx < num_functions; ++func_idx) {
DWARFDIE die = function_dies.GetDIEAtIndex(func_idx);
if (sc.comp_unit->FindFunctionByUID(die.GetID()).get() == NULL) {
if (ParseCompileUnitFunction(sc, die))
++functions_added;
}
}
// FixupTypes();
}
return functions_added;
}
bool SymbolFileDWARF::ParseCompileUnitSupportFiles(
const SymbolContext &sc, FileSpecList &support_files) {
assert(sc.comp_unit);
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu) {
const DWARFDIE cu_die = dwarf_cu->GetCompileUnitDIEOnly();
if (cu_die) {
const char *cu_comp_dir = resolveCompDir(
cu_die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr));
const dw_offset_t stmt_list = cu_die.GetAttributeValueAsUnsigned(
DW_AT_stmt_list, DW_INVALID_OFFSET);
if (stmt_list != DW_INVALID_OFFSET) {
// All file indexes in DWARF are one based and a file of index zero is
// supposed to be the compile unit itself.
support_files.Append(*sc.comp_unit);
return DWARFDebugLine::ParseSupportFiles(
sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir,
stmt_list, support_files);
}
}
}
return false;
}
bool SymbolFileDWARF::ParseCompileUnitIsOptimized(
const lldb_private::SymbolContext &sc) {
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu)
return dwarf_cu->GetIsOptimized();
return false;
}
bool SymbolFileDWARF::ParseImportedModules(
const lldb_private::SymbolContext &sc,
std::vector<lldb_private::ConstString> &imported_modules) {
assert(sc.comp_unit);
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu) {
if (ClangModulesDeclVendor::LanguageSupportsClangModules(
sc.comp_unit->GetLanguage())) {
UpdateExternalModuleListIfNeeded();
if (sc.comp_unit) {
const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly();
if (die) {
for (DWARFDIE child_die = die.GetFirstChild(); child_die;
child_die = child_die.GetSibling()) {
if (child_die.Tag() == DW_TAG_imported_declaration) {
if (DWARFDIE module_die =
child_die.GetReferencedDIE(DW_AT_import)) {
if (module_die.Tag() == DW_TAG_module) {
if (const char *name = module_die.GetAttributeValueAsString(
DW_AT_name, nullptr)) {
ConstString const_name(name);
imported_modules.push_back(const_name);
}
}
}
}
}
}
} else {
for (const auto &pair : m_external_type_modules) {
imported_modules.push_back(pair.first);
}
}
}
}
return false;
}
struct ParseDWARFLineTableCallbackInfo {
LineTable *line_table;
std::unique_ptr<LineSequence> sequence_ap;
lldb::addr_t addr_mask;
};
//----------------------------------------------------------------------
// ParseStatementTableCallback
//----------------------------------------------------------------------
static void ParseDWARFLineTableCallback(dw_offset_t offset,
const DWARFDebugLine::State &state,
void *userData) {
if (state.row == DWARFDebugLine::State::StartParsingLineTable) {
// Just started parsing the line table
} else if (state.row == DWARFDebugLine::State::DoneParsingLineTable) {
// Done parsing line table, nothing to do for the cleanup
} else {
ParseDWARFLineTableCallbackInfo *info =
(ParseDWARFLineTableCallbackInfo *)userData;
LineTable *line_table = info->line_table;
// If this is our first time here, we need to create a
// sequence container.
if (!info->sequence_ap.get()) {
info->sequence_ap.reset(line_table->CreateLineSequenceContainer());
assert(info->sequence_ap.get());
}
line_table->AppendLineEntryToSequence(
info->sequence_ap.get(), state.address & info->addr_mask, state.line,
state.column, state.file, state.is_stmt, state.basic_block,
state.prologue_end, state.epilogue_begin, state.end_sequence);
if (state.end_sequence) {
// First, put the current sequence into the line table.
line_table->InsertSequence(info->sequence_ap.get());
// Then, empty it to prepare for the next sequence.
info->sequence_ap->Clear();
}
}
}
bool SymbolFileDWARF::ParseCompileUnitLineTable(const SymbolContext &sc) {
assert(sc.comp_unit);
if (sc.comp_unit->GetLineTable() != NULL)
return true;
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu) {
const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly();
if (dwarf_cu_die) {
const dw_offset_t cu_line_offset =
dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_stmt_list,
DW_INVALID_OFFSET);
if (cu_line_offset != DW_INVALID_OFFSET) {
std::unique_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit));
if (line_table_ap.get()) {
ParseDWARFLineTableCallbackInfo info;
info.line_table = line_table_ap.get();
/*
* MIPS:
* The SymbolContext may not have a valid target, thus we may not be
* able
* to call Address::GetOpcodeLoadAddress() which would clear the bit
* #0
* for MIPS. Use ArchSpec to clear the bit #0.
*/
ArchSpec arch;
GetObjectFile()->GetArchitecture(arch);
switch (arch.GetMachine()) {
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
info.addr_mask = ~((lldb::addr_t)1);
break;
default:
info.addr_mask = ~((lldb::addr_t)0);
break;
}
lldb::offset_t offset = cu_line_offset;
DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset,
ParseDWARFLineTableCallback,
&info);
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (debug_map_symfile) {
// We have an object file that has a line table with addresses
// that are not linked. We need to link the line table and convert
// the addresses that are relative to the .o file into addresses
// for the main executable.
sc.comp_unit->SetLineTable(
debug_map_symfile->LinkOSOLineTable(this, line_table_ap.get()));
} else {
sc.comp_unit->SetLineTable(line_table_ap.release());
return true;
}
}
}
}
}
return false;
}
lldb_private::DebugMacrosSP
SymbolFileDWARF::ParseDebugMacros(lldb::offset_t *offset) {
auto iter = m_debug_macros_map.find(*offset);
if (iter != m_debug_macros_map.end())
return iter->second;
const DWARFDataExtractor &debug_macro_data = get_debug_macro_data();
if (debug_macro_data.GetByteSize() == 0)
return DebugMacrosSP();
lldb_private::DebugMacrosSP debug_macros_sp(new lldb_private::DebugMacros());
m_debug_macros_map[*offset] = debug_macros_sp;
const DWARFDebugMacroHeader &header =
DWARFDebugMacroHeader::ParseHeader(debug_macro_data, offset);
DWARFDebugMacroEntry::ReadMacroEntries(debug_macro_data, get_debug_str_data(),
header.OffsetIs64Bit(), offset, this,
debug_macros_sp);
return debug_macros_sp;
}
bool SymbolFileDWARF::ParseCompileUnitDebugMacros(const SymbolContext &sc) {
assert(sc.comp_unit);
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu == nullptr)
return false;
const DWARFDIE dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly();
if (!dwarf_cu_die)
return false;
lldb::offset_t sect_offset =
dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_macros, DW_INVALID_OFFSET);
if (sect_offset == DW_INVALID_OFFSET)
sect_offset = dwarf_cu_die.GetAttributeValueAsUnsigned(DW_AT_GNU_macros,
DW_INVALID_OFFSET);
if (sect_offset == DW_INVALID_OFFSET)
return false;
sc.comp_unit->SetDebugMacros(ParseDebugMacros(&sect_offset));
return true;
}
size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc,
Block *parent_block,
const DWARFDIE &orig_die,
addr_t subprogram_low_pc,
uint32_t depth) {
size_t blocks_added = 0;
DWARFDIE die = orig_die;
while (die) {
dw_tag_t tag = die.Tag();
switch (tag) {
case DW_TAG_inlined_subroutine:
case DW_TAG_subprogram:
case DW_TAG_lexical_block: {
Block *block = NULL;
if (tag == DW_TAG_subprogram) {
// Skip any DW_TAG_subprogram DIEs that are inside
// of a normal or inlined functions. These will be
// parsed on their own as separate entities.
if (depth > 0)
break;
block = parent_block;
} else {
BlockSP block_sp(new Block(die.GetID()));
parent_block->AddChild(block_sp);
block = block_sp.get();
}
DWARFRangeList ranges;
const char *name = NULL;
const char *mangled_name = NULL;
int decl_file = 0;
int decl_line = 0;
int decl_column = 0;
int call_file = 0;
int call_line = 0;
int call_column = 0;
if (die.GetDIENamesAndRanges(name, mangled_name, ranges, decl_file,
decl_line, decl_column, call_file, call_line,
call_column, nullptr)) {
if (tag == DW_TAG_subprogram) {
assert(subprogram_low_pc == LLDB_INVALID_ADDRESS);
subprogram_low_pc = ranges.GetMinRangeBase(0);
} else if (tag == DW_TAG_inlined_subroutine) {
// We get called here for inlined subroutines in two ways.
// The first time is when we are making the Function object
// for this inlined concrete instance. Since we're creating a top
// level block at
// here, the subprogram_low_pc will be LLDB_INVALID_ADDRESS. So we
// need to
// adjust the containing address.
// The second time is when we are parsing the blocks inside the
// function that contains
// the inlined concrete instance. Since these will be blocks inside
// the containing "real"
// function the offset will be for that function.
if (subprogram_low_pc == LLDB_INVALID_ADDRESS) {
subprogram_low_pc = ranges.GetMinRangeBase(0);
}
}
const size_t num_ranges = ranges.GetSize();
for (size_t i = 0; i < num_ranges; ++i) {
const DWARFRangeList::Entry &range = ranges.GetEntryRef(i);
const addr_t range_base = range.GetRangeBase();
if (range_base >= subprogram_low_pc)
block->AddRange(Block::Range(range_base - subprogram_low_pc,
range.GetByteSize()));
else {
GetObjectFile()->GetModule()->ReportError(
"0x%8.8" PRIx64 ": adding range [0x%" PRIx64 "-0x%" PRIx64
") which has a base that is less than the function's low PC "
"0x%" PRIx64 ". Please file a bug and attach the file at the "
"start of this error message",
block->GetID(), range_base, range.GetRangeEnd(),
subprogram_low_pc);
}
}
block->FinalizeRanges();
if (tag != DW_TAG_subprogram &&
(name != NULL || mangled_name != NULL)) {
std::unique_ptr<Declaration> decl_ap;
if (decl_file != 0 || decl_line != 0 || decl_column != 0)
decl_ap.reset(new Declaration(
sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file),
decl_line, decl_column));
std::unique_ptr<Declaration> call_ap;
if (call_file != 0 || call_line != 0 || call_column != 0)
call_ap.reset(new Declaration(
sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(call_file),
call_line, call_column));
block->SetInlinedFunctionInfo(name, mangled_name, decl_ap.get(),
call_ap.get());
}
++blocks_added;
if (die.HasChildren()) {
blocks_added += ParseFunctionBlocks(sc, block, die.GetFirstChild(),
subprogram_low_pc, depth + 1);
}
}
} break;
default:
break;
}
// Only parse siblings of the block if we are not at depth zero. A depth
// of zero indicates we are currently parsing the top level
// DW_TAG_subprogram DIE
if (depth == 0)
die.Clear();
else
die = die.GetSibling();
}
return blocks_added;
}
bool SymbolFileDWARF::ClassOrStructIsVirtual(const DWARFDIE &parent_die) {
if (parent_die) {
for (DWARFDIE die = parent_die.GetFirstChild(); die;
die = die.GetSibling()) {
dw_tag_t tag = die.Tag();
bool check_virtuality = false;
switch (tag) {
case DW_TAG_inheritance:
case DW_TAG_subprogram:
check_virtuality = true;
break;
default:
break;
}
if (check_virtuality) {
if (die.GetAttributeValueAsUnsigned(DW_AT_virtuality, 0) != 0)
return true;
}
}
}
return false;
}
void SymbolFileDWARF::ParseDeclsForContext(CompilerDeclContext decl_ctx) {
TypeSystem *type_system = decl_ctx.GetTypeSystem();
DWARFASTParser *ast_parser = type_system->GetDWARFParser();
std::vector<DWARFDIE> decl_ctx_die_list =
ast_parser->GetDIEForDeclContext(decl_ctx);
for (DWARFDIE decl_ctx_die : decl_ctx_die_list)
for (DWARFDIE decl = decl_ctx_die.GetFirstChild(); decl;
decl = decl.GetSibling())
ast_parser->GetDeclForUIDFromDWARF(decl);
}
SymbolFileDWARF *SymbolFileDWARF::GetDWARFForUID(lldb::user_id_t uid) {
// Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API
// we must make sure we use the correct DWARF file when resolving things.
// On MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple
// SymbolFileDWARF classes, one for each .o file. We can often end up
// with references to other DWARF objects and we must be ready to receive
// a "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF
// instance.
SymbolFileDWARFDebugMap *debug_map = GetDebugMapSymfile();
if (debug_map)
return debug_map->GetSymbolFileByOSOIndex(
debug_map->GetOSOIndexFromUserID(uid));
return this;
}
DWARFDIE
SymbolFileDWARF::GetDIEFromUID(lldb::user_id_t uid) {
// Anytime we get a "lldb::user_id_t" from an lldb_private::SymbolFile API
// we must make sure we use the correct DWARF file when resolving things.
// On MacOSX, when using SymbolFileDWARFDebugMap, we will use multiple
// SymbolFileDWARF classes, one for each .o file. We can often end up
// with references to other DWARF objects and we must be ready to receive
// a "lldb::user_id_t" that specifies a DIE from another SymbolFileDWARF
// instance.
SymbolFileDWARF *dwarf = GetDWARFForUID(uid);
if (dwarf)
return dwarf->GetDIE(DIERef(uid, dwarf));
return DWARFDIE();
}
CompilerDecl SymbolFileDWARF::GetDeclForUID(lldb::user_id_t type_uid) {
// Anytime we have a lldb::user_id_t, we must get the DIE by
// calling SymbolFileDWARF::GetDIEFromUID(). See comments inside
// the SymbolFileDWARF::GetDIEFromUID() for details.
DWARFDIE die = GetDIEFromUID(type_uid);
if (die)
return die.GetDecl();
return CompilerDecl();
}
CompilerDeclContext
SymbolFileDWARF::GetDeclContextForUID(lldb::user_id_t type_uid) {
// Anytime we have a lldb::user_id_t, we must get the DIE by
// calling SymbolFileDWARF::GetDIEFromUID(). See comments inside
// the SymbolFileDWARF::GetDIEFromUID() for details.
DWARFDIE die = GetDIEFromUID(type_uid);
if (die)
return die.GetDeclContext();
return CompilerDeclContext();
}
CompilerDeclContext
SymbolFileDWARF::GetDeclContextContainingUID(lldb::user_id_t type_uid) {
// Anytime we have a lldb::user_id_t, we must get the DIE by
// calling SymbolFileDWARF::GetDIEFromUID(). See comments inside
// the SymbolFileDWARF::GetDIEFromUID() for details.
DWARFDIE die = GetDIEFromUID(type_uid);
if (die)
return die.GetContainingDeclContext();
return CompilerDeclContext();
}
Type *SymbolFileDWARF::ResolveTypeUID(lldb::user_id_t type_uid) {
// Anytime we have a lldb::user_id_t, we must get the DIE by
// calling SymbolFileDWARF::GetDIEFromUID(). See comments inside
// the SymbolFileDWARF::GetDIEFromUID() for details.
DWARFDIE type_die = GetDIEFromUID(type_uid);
if (type_die)
return type_die.ResolveType();
else
return nullptr;
}
Type *SymbolFileDWARF::ResolveTypeUID(const DIERef &die_ref) {
return ResolveType(GetDIE(die_ref), true);
}
Type *SymbolFileDWARF::ResolveTypeUID(const DWARFDIE &die,
bool assert_not_being_parsed) {
if (die) {
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
if (log)
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s'",
die.GetOffset(), die.GetTagAsCString(), die.GetName());
// We might be coming in in the middle of a type tree (a class
// within a class, an enum within a class), so parse any needed
// parent DIEs before we get to this one...
DWARFDIE decl_ctx_die = GetDeclContextDIEContainingDIE(die);
if (decl_ctx_die) {
if (log) {
switch (decl_ctx_die.Tag()) {
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_class_type: {
// Get the type, which could be a forward declaration
if (log)
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' "
"resolve parent forward type for 0x%8.8x",
die.GetOffset(), die.GetTagAsCString(), die.GetName(),
decl_ctx_die.GetOffset());
} break;
default:
break;
}
}
}
return ResolveType(die);
}
return NULL;
}
// This function is used when SymbolFileDWARFDebugMap owns a bunch of
// SymbolFileDWARF objects to detect if this DWARF file is the one that
// can resolve a compiler_type.
bool SymbolFileDWARF::HasForwardDeclForClangType(
const CompilerType &compiler_type) {
CompilerType compiler_type_no_qualifiers =
ClangUtil::RemoveFastQualifiers(compiler_type);
if (GetForwardDeclClangTypeToDie().count(
compiler_type_no_qualifiers.GetOpaqueQualType())) {
return true;
}
TypeSystem *type_system = compiler_type.GetTypeSystem();
ClangASTContext *clang_type_system =
llvm::dyn_cast_or_null<ClangASTContext>(type_system);
if (!clang_type_system)
return false;
DWARFASTParserClang *ast_parser =
static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser());
return ast_parser->GetClangASTImporter().CanImport(compiler_type);
}
bool SymbolFileDWARF::CompleteType(CompilerType &compiler_type) {
std::lock_guard<std::recursive_mutex> guard(
GetObjectFile()->GetModule()->GetMutex());
ClangASTContext *clang_type_system =
llvm::dyn_cast_or_null<ClangASTContext>(compiler_type.GetTypeSystem());
if (clang_type_system) {
DWARFASTParserClang *ast_parser =
static_cast<DWARFASTParserClang *>(clang_type_system->GetDWARFParser());
if (ast_parser &&
ast_parser->GetClangASTImporter().CanImport(compiler_type))
return ast_parser->GetClangASTImporter().CompleteType(compiler_type);
}
// We have a struct/union/class/enum that needs to be fully resolved.
CompilerType compiler_type_no_qualifiers =
ClangUtil::RemoveFastQualifiers(compiler_type);
auto die_it = GetForwardDeclClangTypeToDie().find(
compiler_type_no_qualifiers.GetOpaqueQualType());
if (die_it == GetForwardDeclClangTypeToDie().end()) {
// We have already resolved this type...
return true;
}
DWARFDIE dwarf_die = GetDIE(die_it->getSecond());
if (dwarf_die) {
// Once we start resolving this type, remove it from the forward declaration
// map in case anyone child members or other types require this type to get
// resolved.
// The type will get resolved when all of the calls to
// SymbolFileDWARF::ResolveClangOpaqueTypeDefinition
// are done.
GetForwardDeclClangTypeToDie().erase(die_it);
Type *type = GetDIEToType().lookup(dwarf_die.GetDIE());
Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO |
DWARF_LOG_TYPE_COMPLETION));
if (log)
GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...",
dwarf_die.GetID(), dwarf_die.GetTagAsCString(),
type->GetName().AsCString());
assert(compiler_type);
DWARFASTParser *dwarf_ast = dwarf_die.GetDWARFParser();
if (dwarf_ast)
return dwarf_ast->CompleteTypeFromDWARF(dwarf_die, type, compiler_type);
}
return false;
}
Type *SymbolFileDWARF::ResolveType(const DWARFDIE &die,
bool assert_not_being_parsed,
bool resolve_function_context) {
if (die) {
Type *type = GetTypeForDIE(die, resolve_function_context).get();
if (assert_not_being_parsed) {
if (type != DIE_IS_BEING_PARSED)
return type;
GetObjectFile()->GetModule()->ReportError(
"Parsing a die that is being parsed die: 0x%8.8x: %s %s",
die.GetOffset(), die.GetTagAsCString(), die.GetName());
} else
return type;
}
return nullptr;
}
CompileUnit *
SymbolFileDWARF::GetCompUnitForDWARFCompUnit(DWARFCompileUnit *dwarf_cu,
uint32_t cu_idx) {
// Check if the symbol vendor already knows about this compile unit?
if (dwarf_cu->GetUserData() == NULL) {
// The symbol vendor doesn't know about this compile unit, we
// need to parse and add it to the symbol vendor object.
return ParseCompileUnit(dwarf_cu, cu_idx).get();
}
return (CompileUnit *)dwarf_cu->GetUserData();
}
size_t SymbolFileDWARF::GetObjCMethodDIEOffsets(ConstString class_name,
DIEArray &method_die_offsets) {
method_die_offsets.clear();
if (m_using_apple_tables) {
if (m_apple_objc_ap.get())
m_apple_objc_ap->FindByName(class_name.GetCString(), method_die_offsets);
} else {
if (!m_indexed)
Index();
m_objc_class_selectors_index.Find(class_name, method_die_offsets);
}
return method_die_offsets.size();
}
bool SymbolFileDWARF::GetFunction(const DWARFDIE &die, SymbolContext &sc) {
sc.Clear(false);
if (die) {
// Check if the symbol vendor already knows about this compile unit?
sc.comp_unit = GetCompUnitForDWARFCompUnit(die.GetCU(), UINT32_MAX);
sc.function = sc.comp_unit->FindFunctionByUID(die.GetID()).get();
if (sc.function == NULL)
sc.function = ParseCompileUnitFunction(sc, die);
if (sc.function) {
sc.module_sp = sc.function->CalculateSymbolContextModule();
return true;
}
}
return false;
}
lldb::ModuleSP SymbolFileDWARF::GetDWOModule(ConstString name) {
UpdateExternalModuleListIfNeeded();
const auto &pos = m_external_type_modules.find(name);
if (pos != m_external_type_modules.end())
return pos->second;
else
return lldb::ModuleSP();
}
DWARFDIE
SymbolFileDWARF::GetDIE(const DIERef &die_ref) {
DWARFDebugInfo *debug_info = DebugInfo();
if (debug_info)
return debug_info->GetDIE(die_ref);
else
return DWARFDIE();
}
std::unique_ptr<SymbolFileDWARFDwo>
SymbolFileDWARF::GetDwoSymbolFileForCompileUnit(
DWARFCompileUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) {
// If we are using a dSYM file, we never want the standard DWO files since
// the -gmodule support uses the same DWO machanism to specify full debug
// info files for modules.
if (GetDebugMapSymfile())
return nullptr;
const char *dwo_name = cu_die.GetAttributeValueAsString(
this, &dwarf_cu, DW_AT_GNU_dwo_name, nullptr);
if (!dwo_name)
return nullptr;
SymbolFileDWARFDwp *dwp_symfile = GetDwpSymbolFile();
if (dwp_symfile) {
uint64_t dwo_id = cu_die.GetAttributeValueAsUnsigned(this, &dwarf_cu,
DW_AT_GNU_dwo_id, 0);
std::unique_ptr<SymbolFileDWARFDwo> dwo_symfile =
dwp_symfile->GetSymbolFileForDwoId(&dwarf_cu, dwo_id);
if (dwo_symfile)
return dwo_symfile;
}
FileSpec dwo_file(dwo_name, true);
if (dwo_file.IsRelative()) {
const char *comp_dir = cu_die.GetAttributeValueAsString(
this, &dwarf_cu, DW_AT_comp_dir, nullptr);
if (!comp_dir)
return nullptr;
dwo_file.SetFile(comp_dir, true);
dwo_file.AppendPathComponent(dwo_name);
}
if (!dwo_file.Exists())
return nullptr;
const lldb::offset_t file_offset = 0;
DataBufferSP dwo_file_data_sp;
lldb::offset_t dwo_file_data_offset = 0;
ObjectFileSP dwo_obj_file = ObjectFile::FindPlugin(
GetObjectFile()->GetModule(), &dwo_file, file_offset,
dwo_file.GetByteSize(), dwo_file_data_sp, dwo_file_data_offset);
if (dwo_obj_file == nullptr)
return nullptr;
return llvm::make_unique<SymbolFileDWARFDwo>(dwo_obj_file, &dwarf_cu);
}
void SymbolFileDWARF::UpdateExternalModuleListIfNeeded() {
if (m_fetched_external_modules)
return;
m_fetched_external_modules = true;
DWARFDebugInfo *debug_info = DebugInfo();
const uint32_t num_compile_units = GetNumCompileUnits();
for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) {
DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
const DWARFDIE die = dwarf_cu->GetCompileUnitDIEOnly();
if (die && die.HasChildren() == false) {
const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr);
if (name) {
ConstString const_name(name);
if (m_external_type_modules.find(const_name) ==
m_external_type_modules.end()) {
ModuleSP module_sp;
const char *dwo_path =
die.GetAttributeValueAsString(DW_AT_GNU_dwo_name, nullptr);
if (dwo_path) {
ModuleSpec dwo_module_spec;
dwo_module_spec.GetFileSpec().SetFile(dwo_path, false);
if (dwo_module_spec.GetFileSpec().IsRelative()) {
const char *comp_dir =
die.GetAttributeValueAsString(DW_AT_comp_dir, nullptr);
if (comp_dir) {
dwo_module_spec.GetFileSpec().SetFile(comp_dir, true);
dwo_module_spec.GetFileSpec().AppendPathComponent(dwo_path);
}
}
dwo_module_spec.GetArchitecture() =
m_obj_file->GetModule()->GetArchitecture();
// When LLDB loads "external" modules it looks at the
// presence of DW_AT_GNU_dwo_name.
// However, when the already created module
// (corresponding to .dwo itself) is being processed,
// it will see the presence of DW_AT_GNU_dwo_name
// (which contains the name of dwo file) and
// will try to call ModuleList::GetSharedModule again.
// In some cases (i.e. for empty files) Clang 4.0
// generates a *.dwo file which has DW_AT_GNU_dwo_name,
// but no DW_AT_comp_dir. In this case the method
// ModuleList::GetSharedModule will fail and
// the warning will be printed. However, as one can notice
// in this case we don't actually need to try to load the already
// loaded module (corresponding to .dwo) so we simply skip it.
if (m_obj_file->GetFileSpec()
.GetFileNameExtension()
.GetStringRef() == "dwo" &&
llvm::StringRef(m_obj_file->GetFileSpec().GetPath())
.endswith(dwo_module_spec.GetFileSpec().GetPath())) {
continue;
}
Status error = ModuleList::GetSharedModule(
dwo_module_spec, module_sp, NULL, NULL, NULL);
if (!module_sp) {
GetObjectFile()->GetModule()->ReportWarning(
"0x%8.8x: unable to locate module needed for external types: "
"%s\nerror: %s\nDebugging will be degraded due to missing "
"types. Rebuilding your project will regenerate the needed "
"module files.",
die.GetOffset(),
dwo_module_spec.GetFileSpec().GetPath().c_str(),
error.AsCString("unknown error"));
}
}
m_external_type_modules[const_name] = module_sp;
}
}
}
}
}
SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() {
if (!m_global_aranges_ap) {
m_global_aranges_ap.reset(new GlobalVariableMap());
ModuleSP module_sp = GetObjectFile()->GetModule();
if (module_sp) {
const size_t num_cus = module_sp->GetNumCompileUnits();
for (size_t i = 0; i < num_cus; ++i) {
CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(i);
if (cu_sp) {
VariableListSP globals_sp = cu_sp->GetVariableList(true);
if (globals_sp) {
const size_t num_globals = globals_sp->GetSize();
for (size_t g = 0; g < num_globals; ++g) {
VariableSP var_sp = globals_sp->GetVariableAtIndex(g);
if (var_sp && !var_sp->GetLocationIsConstantValueData()) {
const DWARFExpression &location = var_sp->LocationExpression();
Value location_result;
Status error;
if (location.Evaluate(nullptr, LLDB_INVALID_ADDRESS, nullptr,
nullptr, location_result, &error)) {
if (location_result.GetValueType() ==
Value::eValueTypeFileAddress) {
lldb::addr_t file_addr =
location_result.GetScalar().ULongLong();
lldb::addr_t byte_size = 1;
if (var_sp->GetType())
byte_size = var_sp->GetType()->GetByteSize();
m_global_aranges_ap->Append(GlobalVariableMap::Entry(
file_addr, byte_size, var_sp.get()));
}
}
}
}
}
}
}
}
m_global_aranges_ap->Sort();
}
return *m_global_aranges_ap;
}
uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr,
uint32_t resolve_scope,
SymbolContext &sc) {
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(func_cat,
"SymbolFileDWARF::"
"ResolveSymbolContext (so_addr = { "
"section = %p, offset = 0x%" PRIx64
" }, resolve_scope = 0x%8.8x)",
static_cast<void *>(so_addr.GetSection().get()),
so_addr.GetOffset(), resolve_scope);
uint32_t resolved = 0;
if (resolve_scope &
(eSymbolContextCompUnit | eSymbolContextFunction | eSymbolContextBlock |
eSymbolContextLineEntry | eSymbolContextVariable)) {
lldb::addr_t file_vm_addr = so_addr.GetFileAddress();
DWARFDebugInfo *debug_info = DebugInfo();
if (debug_info) {
const dw_offset_t cu_offset =
debug_info->GetCompileUnitAranges().FindAddress(file_vm_addr);
if (cu_offset == DW_INVALID_OFFSET) {
// Global variables are not in the compile unit address ranges. The only
// way to
// currently find global variables is to iterate over the
// .debug_pubnames or the
// __apple_names table and find all items in there that point to
// DW_TAG_variable
// DIEs and then find the address that matches.
if (resolve_scope & eSymbolContextVariable) {
GlobalVariableMap &map = GetGlobalAranges();
const GlobalVariableMap::Entry *entry =
map.FindEntryThatContains(file_vm_addr);
if (entry && entry->data) {
Variable *variable = entry->data;
SymbolContextScope *scc = variable->GetSymbolContextScope();
if (scc) {
scc->CalculateSymbolContext(&sc);
sc.variable = variable;
}
return sc.GetResolvedMask();
}
}
} else {
uint32_t cu_idx = DW_INVALID_INDEX;
DWARFCompileUnit *dwarf_cu =
debug_info->GetCompileUnit(cu_offset, &cu_idx);
if (dwarf_cu) {
sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
if (sc.comp_unit) {
resolved |= eSymbolContextCompUnit;
bool force_check_line_table = false;
if (resolve_scope &
(eSymbolContextFunction | eSymbolContextBlock)) {
DWARFDIE function_die = dwarf_cu->LookupAddress(file_vm_addr);
DWARFDIE block_die;
if (function_die) {
sc.function =
sc.comp_unit->FindFunctionByUID(function_die.GetID()).get();
if (sc.function == NULL)
sc.function = ParseCompileUnitFunction(sc, function_die);
if (sc.function && (resolve_scope & eSymbolContextBlock))
block_die = function_die.LookupDeepestBlock(file_vm_addr);
} else {
// We might have had a compile unit that had discontiguous
// address ranges where the gaps are symbols that don't have
// any debug info. Discontiguous compile unit address ranges
// should only happen when there aren't other functions from
// other compile units in these gaps. This helps keep the size
// of the aranges down.
force_check_line_table = true;
}
if (sc.function != NULL) {
resolved |= eSymbolContextFunction;
if (resolve_scope & eSymbolContextBlock) {
Block &block = sc.function->GetBlock(true);
if (block_die)
sc.block = block.FindBlockByID(block_die.GetID());
else
sc.block = block.FindBlockByID(function_die.GetID());
if (sc.block)
resolved |= eSymbolContextBlock;
}
}
}
if ((resolve_scope & eSymbolContextLineEntry) ||
force_check_line_table) {
LineTable *line_table = sc.comp_unit->GetLineTable();
if (line_table != NULL) {
// And address that makes it into this function should be in
// terms
// of this debug file if there is no debug map, or it will be an
// address in the .o file which needs to be fixed up to be in
// terms
// of the debug map executable. Either way, calling
// FixupAddress()
// will work for us.
Address exe_so_addr(so_addr);
if (FixupAddress(exe_so_addr)) {
if (line_table->FindLineEntryByAddress(exe_so_addr,
sc.line_entry)) {
resolved |= eSymbolContextLineEntry;
}
}
}
}
if (force_check_line_table &&
!(resolved & eSymbolContextLineEntry)) {
// We might have had a compile unit that had discontiguous
// address ranges where the gaps are symbols that don't have
// any debug info. Discontiguous compile unit address ranges
// should only happen when there aren't other functions from
// other compile units in these gaps. This helps keep the size
// of the aranges down.
sc.comp_unit = NULL;
resolved &= ~eSymbolContextCompUnit;
}
} else {
GetObjectFile()->GetModule()->ReportWarning(
"0x%8.8x: compile unit %u failed to create a valid "
"lldb_private::CompileUnit class.",
cu_offset, cu_idx);
}
}
}
}
}
return resolved;
}
uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec,
uint32_t line,
bool check_inlines,
uint32_t resolve_scope,
SymbolContextList &sc_list) {
const uint32_t prev_size = sc_list.GetSize();
if (resolve_scope & eSymbolContextCompUnit) {
DWARFDebugInfo *debug_info = DebugInfo();
if (debug_info) {
uint32_t cu_idx;
DWARFCompileUnit *dwarf_cu = NULL;
for (cu_idx = 0;
(dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL;
++cu_idx) {
CompileUnit *dc_cu = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
const bool full_match = (bool)file_spec.GetDirectory();
bool file_spec_matches_cu_file_spec =
dc_cu != NULL && FileSpec::Equal(file_spec, *dc_cu, full_match);
if (check_inlines || file_spec_matches_cu_file_spec) {
SymbolContext sc(m_obj_file->GetModule());
sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
if (sc.comp_unit) {
uint32_t file_idx = UINT32_MAX;
// If we are looking for inline functions only and we don't
// find it in the support files, we are done.
if (check_inlines) {
file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex(
1, file_spec, true);
if (file_idx == UINT32_MAX)
continue;
}
if (line != 0) {
LineTable *line_table = sc.comp_unit->GetLineTable();
if (line_table != NULL && line != 0) {
// We will have already looked up the file index if
// we are searching for inline entries.
if (!check_inlines)
file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex(
1, file_spec, true);
if (file_idx != UINT32_MAX) {
uint32_t found_line;
uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex(
0, file_idx, line, false, &sc.line_entry);
found_line = sc.line_entry.line;
while (line_idx != UINT32_MAX) {
sc.function = NULL;
sc.block = NULL;
if (resolve_scope &
(eSymbolContextFunction | eSymbolContextBlock)) {
const lldb::addr_t file_vm_addr =
sc.line_entry.range.GetBaseAddress().GetFileAddress();
if (file_vm_addr != LLDB_INVALID_ADDRESS) {
DWARFDIE function_die =
dwarf_cu->LookupAddress(file_vm_addr);
DWARFDIE block_die;
if (function_die) {
sc.function =
sc.comp_unit
->FindFunctionByUID(function_die.GetID())
.get();
if (sc.function == NULL)
sc.function =
ParseCompileUnitFunction(sc, function_die);
if (sc.function &&
(resolve_scope & eSymbolContextBlock))
block_die =
function_die.LookupDeepestBlock(file_vm_addr);
}
if (sc.function != NULL) {
Block &block = sc.function->GetBlock(true);
if (block_die)
sc.block = block.FindBlockByID(block_die.GetID());
else if (function_die)
sc.block =
block.FindBlockByID(function_die.GetID());
}
}
}
sc_list.Append(sc);
line_idx = line_table->FindLineEntryIndexByFileIndex(
line_idx + 1, file_idx, found_line, true,
&sc.line_entry);
}
}
} else if (file_spec_matches_cu_file_spec && !check_inlines) {
// only append the context if we aren't looking for inline call
// sites
// by file and line and if the file spec matches that of the
// compile unit
sc_list.Append(sc);
}
} else if (file_spec_matches_cu_file_spec && !check_inlines) {
// only append the context if we aren't looking for inline call
// sites
// by file and line and if the file spec matches that of the
// compile unit
sc_list.Append(sc);
}
if (!check_inlines)
break;
}
}
}
}
}
return sc_list.GetSize() - prev_size;
}
void SymbolFileDWARF::PreloadSymbols() {
std::lock_guard<std::recursive_mutex> guard(
GetObjectFile()->GetModule()->GetMutex());
Index();
}
void SymbolFileDWARF::Index() {
if (m_indexed)
return;
m_indexed = true;
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(
func_cat, "SymbolFileDWARF::Index (%s)",
GetObjectFile()->GetFileSpec().GetFilename().AsCString("<Unknown>"));
DWARFDebugInfo *debug_info = DebugInfo();
if (debug_info) {
const uint32_t num_compile_units = GetNumCompileUnits();
if (num_compile_units == 0)
return;
std::vector<NameToDIE> function_basename_index(num_compile_units);
std::vector<NameToDIE> function_fullname_index(num_compile_units);
std::vector<NameToDIE> function_method_index(num_compile_units);
std::vector<NameToDIE> function_selector_index(num_compile_units);
std::vector<NameToDIE> objc_class_selectors_index(num_compile_units);
std::vector<NameToDIE> global_index(num_compile_units);
std::vector<NameToDIE> type_index(num_compile_units);
std::vector<NameToDIE> namespace_index(num_compile_units);
// std::vector<bool> might be implemented using bit test-and-set, so use
// uint8_t instead.
std::vector<uint8_t> clear_cu_dies(num_compile_units, false);
auto parser_fn = [debug_info, &function_basename_index,
&function_fullname_index, &function_method_index,
&function_selector_index, &objc_class_selectors_index,
&global_index, &type_index,
&namespace_index](size_t cu_idx) {
DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
if (dwarf_cu) {
dwarf_cu->Index(
function_basename_index[cu_idx], function_fullname_index[cu_idx],
function_method_index[cu_idx], function_selector_index[cu_idx],
objc_class_selectors_index[cu_idx], global_index[cu_idx],
type_index[cu_idx], namespace_index[cu_idx]);
}
};
auto extract_fn = [debug_info, &clear_cu_dies](size_t cu_idx) {
DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
if (dwarf_cu) {
// dwarf_cu->ExtractDIEsIfNeeded(false) will return zero if the
// DIEs for a compile unit have already been parsed.
if (dwarf_cu->ExtractDIEsIfNeeded(false) > 1)
clear_cu_dies[cu_idx] = true;
}
};
// Create a task runner that extracts dies for each DWARF compile unit in a
// separate thread
//----------------------------------------------------------------------
// First figure out which compile units didn't have their DIEs already
// parsed and remember this. If no DIEs were parsed prior to this index
// function call, we are going to want to clear the CU dies after we
// are done indexing to make sure we don't pull in all DWARF dies, but
// we need to wait until all compile units have been indexed in case
// a DIE in one compile unit refers to another and the indexes accesses
// those DIEs.
//----------------------------------------------------------------------
TaskMapOverInt(0, num_compile_units, extract_fn);
// Now create a task runner that can index each DWARF compile unit in a
// separate
// thread so we can index quickly.
TaskMapOverInt(0, num_compile_units, parser_fn);
auto finalize_fn = [](NameToDIE &index, std::vector<NameToDIE> &srcs) {
for (auto &src : srcs)
index.Append(src);
index.Finalize();
};
TaskPool::RunTasks(
[&]() {
finalize_fn(m_function_basename_index, function_basename_index);
},
[&]() {
finalize_fn(m_function_fullname_index, function_fullname_index);
},
[&]() { finalize_fn(m_function_method_index, function_method_index); },
[&]() {
finalize_fn(m_function_selector_index, function_selector_index);
},
[&]() {
finalize_fn(m_objc_class_selectors_index, objc_class_selectors_index);
},
[&]() { finalize_fn(m_global_index, global_index); },
[&]() { finalize_fn(m_type_index, type_index); },
[&]() { finalize_fn(m_namespace_index, namespace_index); });
//----------------------------------------------------------------------
// Keep memory down by clearing DIEs for any compile units if indexing
// caused us to load the compile unit's DIEs.
//----------------------------------------------------------------------
for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) {
if (clear_cu_dies[cu_idx])
debug_info->GetCompileUnitAtIndex(cu_idx)->ClearDIEs(true);
}
#if defined(ENABLE_DEBUG_PRINTF)
StreamFile s(stdout, false);
s.Printf("DWARF index for '%s':",
GetObjectFile()->GetFileSpec().GetPath().c_str());
s.Printf("\nFunction basenames:\n");
m_function_basename_index.Dump(&s);
s.Printf("\nFunction fullnames:\n");
m_function_fullname_index.Dump(&s);
s.Printf("\nFunction methods:\n");
m_function_method_index.Dump(&s);
s.Printf("\nFunction selectors:\n");
m_function_selector_index.Dump(&s);
s.Printf("\nObjective C class selectors:\n");
m_objc_class_selectors_index.Dump(&s);
s.Printf("\nGlobals and statics:\n");
m_global_index.Dump(&s);
s.Printf("\nTypes:\n");
m_type_index.Dump(&s);
s.Printf("\nNamespaces:\n");
m_namespace_index.Dump(&s);
#endif
}
}
bool SymbolFileDWARF::DeclContextMatchesThisSymbolFile(
const lldb_private::CompilerDeclContext *decl_ctx) {
if (decl_ctx == nullptr || !decl_ctx->IsValid()) {
// Invalid namespace decl which means we aren't matching only things
// in this symbol file, so return true to indicate it matches this
// symbol file.
return true;
}
TypeSystem *decl_ctx_type_system = decl_ctx->GetTypeSystem();
TypeSystem *type_system = GetTypeSystemForLanguage(
decl_ctx_type_system->GetMinimumLanguage(nullptr));
if (decl_ctx_type_system == type_system)
return true; // The type systems match, return true
// The namespace AST was valid, and it does not match...
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log)
GetObjectFile()->GetModule()->LogMessage(
log, "Valid namespace does not match symbol file");
return false;
}
uint32_t SymbolFileDWARF::FindGlobalVariables(
const ConstString &name, const CompilerDeclContext *parent_decl_ctx,
bool append, uint32_t max_matches, VariableList &variables) {
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log)
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", "
"parent_decl_ctx=%p, append=%u, max_matches=%u, variables)",
name.GetCString(), static_cast<const void *>(parent_decl_ctx), append,
max_matches);
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return 0;
DWARFDebugInfo *info = DebugInfo();
if (info == NULL)
return 0;
// If we aren't appending the results to this list, then clear the list
if (!append)
variables.Clear();
// Remember how many variables are in the list before we search in case
// we are appending the results to a variable list.
const uint32_t original_size = variables.GetSize();
DIEArray die_offsets;
if (m_using_apple_tables) {
if (m_apple_names_ap.get()) {
const char *name_cstr = name.GetCString();
llvm::StringRef basename;
llvm::StringRef context;
if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name_cstr, context,
basename))
basename = name_cstr;
m_apple_names_ap->FindByName(basename.data(), die_offsets);
}
} else {
// Index the DWARF if we haven't already
if (!m_indexed)
Index();
m_global_index.Find(name, die_offsets);
}
const size_t num_die_matches = die_offsets.size();
if (num_die_matches) {
SymbolContext sc;
sc.module_sp = m_obj_file->GetModule();
assert(sc.module_sp);
bool done = false;
for (size_t i = 0; i < num_die_matches && !done; ++i) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = GetDIE(die_ref);
if (die) {
switch (die.Tag()) {
default:
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_try_block:
case DW_TAG_catch_block:
break;
case DW_TAG_variable: {
sc.comp_unit = GetCompUnitForDWARFCompUnit(die.GetCU(), UINT32_MAX);
if (parent_decl_ctx) {
DWARFASTParser *dwarf_ast = die.GetDWARFParser();
if (dwarf_ast) {
CompilerDeclContext actual_parent_decl_ctx =
dwarf_ast->GetDeclContextContainingUIDFromDWARF(die);
if (!actual_parent_decl_ctx ||
actual_parent_decl_ctx != *parent_decl_ctx)
continue;
}
}
ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false,
&variables);
if (variables.GetSize() - original_size >= max_matches)
done = true;
} break;
}
} else {
if (m_using_apple_tables) {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (.apple_names "
"accelerator table had bad die 0x%8.8x for '%s')\n",
die_ref.die_offset, name.GetCString());
}
}
}
}
// Return the number of variable that were appended to the list
const uint32_t num_matches = variables.GetSize() - original_size;
if (log && num_matches > 0) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", "
"parent_decl_ctx=%p, append=%u, max_matches=%u, variables) => %u",
name.GetCString(), static_cast<const void *>(parent_decl_ctx), append,
max_matches, num_matches);
}
return num_matches;
}
uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression &regex,
bool append, uint32_t max_matches,
VariableList &variables) {
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, "
"max_matches=%u, variables)",
regex.GetText().str().c_str(), append, max_matches);
}
DWARFDebugInfo *info = DebugInfo();
if (info == NULL)
return 0;
// If we aren't appending the results to this list, then clear the list
if (!append)
variables.Clear();
// Remember how many variables are in the list before we search in case
// we are appending the results to a variable list.
const uint32_t original_size = variables.GetSize();
DIEArray die_offsets;
if (m_using_apple_tables) {
if (m_apple_names_ap.get()) {
DWARFMappedHash::DIEInfoArray hash_data_array;
if (m_apple_names_ap->AppendAllDIEsThatMatchingRegex(regex,
hash_data_array))
DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets);
}
} else {
// Index the DWARF if we haven't already
if (!m_indexed)
Index();
m_global_index.Find(regex, die_offsets);
}
SymbolContext sc;
sc.module_sp = m_obj_file->GetModule();
assert(sc.module_sp);
const size_t num_matches = die_offsets.size();
if (num_matches) {
for (size_t i = 0; i < num_matches; ++i) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = GetDIE(die_ref);
if (die) {
sc.comp_unit = GetCompUnitForDWARFCompUnit(die.GetCU(), UINT32_MAX);
ParseVariables(sc, die, LLDB_INVALID_ADDRESS, false, false, &variables);
if (variables.GetSize() - original_size >= max_matches)
break;
} else {
if (m_using_apple_tables) {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (.apple_names "
"accelerator table had bad die 0x%8.8x for regex '%s')\n",
die_ref.die_offset, regex.GetText().str().c_str());
}
}
}
}
// Return the number of variable that were appended to the list
return variables.GetSize() - original_size;
}
bool SymbolFileDWARF::ResolveFunction(const DIERef &die_ref,
bool include_inlines,
SymbolContextList &sc_list) {
DWARFDIE die = DebugInfo()->GetDIE(die_ref);
return ResolveFunction(die, include_inlines, sc_list);
}
bool SymbolFileDWARF::ResolveFunction(const DWARFDIE &orig_die,
bool include_inlines,
SymbolContextList &sc_list) {
SymbolContext sc;
if (!orig_die)
return false;
// If we were passed a die that is not a function, just return false...
if (!(orig_die.Tag() == DW_TAG_subprogram ||
(include_inlines && orig_die.Tag() == DW_TAG_inlined_subroutine)))
return false;
DWARFDIE die = orig_die;
DWARFDIE inlined_die;
if (die.Tag() == DW_TAG_inlined_subroutine) {
inlined_die = die;
while (1) {
die = die.GetParent();
if (die) {
if (die.Tag() == DW_TAG_subprogram)
break;
} else
break;
}
}
assert(die && die.Tag() == DW_TAG_subprogram);
if (GetFunction(die, sc)) {
Address addr;
// Parse all blocks if needed
if (inlined_die) {
Block &function_block = sc.function->GetBlock(true);
sc.block = function_block.FindBlockByID(inlined_die.GetID());
if (sc.block == NULL)
sc.block = function_block.FindBlockByID(inlined_die.GetOffset());
if (sc.block == NULL || sc.block->GetStartAddress(addr) == false)
addr.Clear();
} else {
sc.block = NULL;
addr = sc.function->GetAddressRange().GetBaseAddress();
}
if (addr.IsValid()) {
sc_list.Append(sc);
return true;
}
}
return false;
}
void SymbolFileDWARF::FindFunctions(const ConstString &name,
const NameToDIE &name_to_die,
bool include_inlines,
SymbolContextList &sc_list) {
DIEArray die_offsets;
if (name_to_die.Find(name, die_offsets)) {
ParseFunctions(die_offsets, include_inlines, sc_list);
}
}
void SymbolFileDWARF::FindFunctions(const RegularExpression &regex,
const NameToDIE &name_to_die,
bool include_inlines,
SymbolContextList &sc_list) {
DIEArray die_offsets;
if (name_to_die.Find(regex, die_offsets)) {
ParseFunctions(die_offsets, include_inlines, sc_list);
}
}
void SymbolFileDWARF::FindFunctions(
const RegularExpression &regex,
const DWARFMappedHash::MemoryTable &memory_table, bool include_inlines,
SymbolContextList &sc_list) {
DIEArray die_offsets;
DWARFMappedHash::DIEInfoArray hash_data_array;
if (memory_table.AppendAllDIEsThatMatchingRegex(regex, hash_data_array)) {
DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets);
ParseFunctions(die_offsets, include_inlines, sc_list);
}
}
void SymbolFileDWARF::ParseFunctions(const DIEArray &die_offsets,
bool include_inlines,
SymbolContextList &sc_list) {
const size_t num_matches = die_offsets.size();
if (num_matches) {
for (size_t i = 0; i < num_matches; ++i)
ResolveFunction(die_offsets[i], include_inlines, sc_list);
}
}
bool SymbolFileDWARF::DIEInDeclContext(const CompilerDeclContext *decl_ctx,
const DWARFDIE &die) {
// If we have no parent decl context to match this DIE matches, and if the
// parent
// decl context isn't valid, we aren't trying to look for any particular decl
// context so any die matches.
if (decl_ctx == nullptr || !decl_ctx->IsValid())
return true;
if (die) {
DWARFASTParser *dwarf_ast = die.GetDWARFParser();
if (dwarf_ast) {
CompilerDeclContext actual_decl_ctx =
dwarf_ast->GetDeclContextContainingUIDFromDWARF(die);
if (actual_decl_ctx)
return actual_decl_ctx == *decl_ctx;
}
}
return false;
}
uint32_t
SymbolFileDWARF::FindFunctions(const ConstString &name,
const CompilerDeclContext *parent_decl_ctx,
uint32_t name_type_mask, bool include_inlines,
bool append, SymbolContextList &sc_list) {
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (name = '%s')",
name.AsCString());
// eFunctionNameTypeAuto should be pre-resolved by a call to
// Module::LookupInfo::LookupInfo()
assert((name_type_mask & eFunctionNameTypeAuto) == 0);
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindFunctions (name=\"%s\", "
"name_type_mask=0x%x, append=%u, sc_list)",
name.GetCString(), name_type_mask, append);
}
// If we aren't appending the results to this list, then clear the list
if (!append)
sc_list.Clear();
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return 0;
// If name is empty then we won't find anything.
if (name.IsEmpty())
return 0;
// Remember how many sc_list are in the list before we search in case
// we are appending the results to a variable list.
const char *name_cstr = name.GetCString();
const uint32_t original_size = sc_list.GetSize();
DWARFDebugInfo *info = DebugInfo();
if (info == NULL)
return 0;
std::set<const DWARFDebugInfoEntry *> resolved_dies;
if (m_using_apple_tables) {
if (m_apple_names_ap.get()) {
DIEArray die_offsets;
uint32_t num_matches = 0;
if (name_type_mask & eFunctionNameTypeFull) {
// If they asked for the full name, match what they typed. At some
// point we may
// want to canonicalize this (strip double spaces, etc. For now, we
// just add all the
// dies that we find by exact match.
num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets);
for (uint32_t i = 0; i < num_matches; i++) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = info->GetDIE(die_ref);
if (die) {
if (!DIEInDeclContext(parent_decl_ctx, die))
continue; // The containing decl contexts don't match
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
if (ResolveFunction(die, include_inlines, sc_list))
resolved_dies.insert(die.GetDIE());
}
} else {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (.apple_names "
"accelerator table had bad die 0x%8.8x for '%s')",
die_ref.die_offset, name_cstr);
}
}
}
if (name_type_mask & eFunctionNameTypeSelector) {
if (parent_decl_ctx && parent_decl_ctx->IsValid())
return 0; // no selectors in namespaces
num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets);
// Now make sure these are actually ObjC methods. In this case we can
// simply look up the name,
// and if it is an ObjC method name, we're good.
for (uint32_t i = 0; i < num_matches; i++) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = info->GetDIE(die_ref);
if (die) {
const char *die_name = die.GetName();
if (ObjCLanguage::IsPossibleObjCMethodName(die_name)) {
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
if (ResolveFunction(die, include_inlines, sc_list))
resolved_dies.insert(die.GetDIE());
}
}
} else {
GetObjectFile()->GetModule()->ReportError(
"the DWARF debug information has been modified (.apple_names "
"accelerator table had bad die 0x%8.8x for '%s')",
die_ref.die_offset, name_cstr);
}
}
die_offsets.clear();
}
if (((name_type_mask & eFunctionNameTypeMethod) && !parent_decl_ctx) ||
name_type_mask & eFunctionNameTypeBase) {
// The apple_names table stores just the "base name" of C++ methods in
// the table. So we have to
// extract the base name, look that up, and if there is any other
// information in the name we were
// passed in we have to post-filter based on that.
// FIXME: Arrange the logic above so that we don't calculate the base
// name twice:
num_matches = m_apple_names_ap->FindByName(name_cstr, die_offsets);
for (uint32_t i = 0; i < num_matches; i++) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = info->GetDIE(die_ref);
if (die) {
if (!DIEInDeclContext(parent_decl_ctx, die))
continue; // The containing decl contexts don't match
// If we get to here, the die is good, and we should add it:
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end() &&
ResolveFunction(die, include_inlines, sc_list)) {
bool keep_die = true;
if ((name_type_mask &
(eFunctionNameTypeBase | eFunctionNameTypeMethod)) !=
(eFunctionNameTypeBase | eFunctionNameTypeMethod)) {
// We are looking for either basenames or methods, so we need to
// trim out the ones we won't want by looking at the type
SymbolContext sc;
if (sc_list.GetLastContext(sc)) {
if (sc.block) {
// We have an inlined function
} else if (sc.function) {
Type *type = sc.function->GetType();
if (type) {
CompilerDeclContext decl_ctx =
GetDeclContextContainingUID(type->GetID());
if (decl_ctx.IsStructUnionOrClass()) {
if (name_type_mask & eFunctionNameTypeBase) {
sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1);
keep_die = false;
}
} else {
if (name_type_mask & eFunctionNameTypeMethod) {
sc_list.RemoveContextAtIndex(sc_list.GetSize() - 1);
keep_die = false;
}
}
} else {
GetObjectFile()->GetModule()->ReportWarning(
"function at die offset 0x%8.8x had no function type",
die_ref.die_offset);
}
}
}
}
if (keep_die)
resolved_dies.insert(die.GetDIE());
}
} else {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (.apple_names "
"accelerator table had bad die 0x%8.8x for '%s')",
die_ref.die_offset, name_cstr);
}
}
die_offsets.clear();
}
}
} else {
// Index the DWARF if we haven't already
if (!m_indexed)
Index();
if (name_type_mask & eFunctionNameTypeFull) {
FindFunctions(name, m_function_fullname_index, include_inlines, sc_list);
// FIXME Temporary workaround for global/anonymous namespace
// functions debugging FreeBSD and Linux binaries.
// If we didn't find any functions in the global namespace try
// looking in the basename index but ignore any returned
// functions that have a namespace but keep functions which
// have an anonymous namespace
// TODO: The arch in the object file isn't correct for MSVC
// binaries on windows, we should find a way to make it
// correct and handle those symbols as well.
if (sc_list.GetSize() == original_size) {
ArchSpec arch;
if (!parent_decl_ctx && GetObjectFile()->GetArchitecture(arch) &&
arch.GetTriple().isOSBinFormatELF()) {
SymbolContextList temp_sc_list;
FindFunctions(name, m_function_basename_index, include_inlines,
temp_sc_list);
SymbolContext sc;
for (uint32_t i = 0; i < temp_sc_list.GetSize(); i++) {
if (temp_sc_list.GetContextAtIndex(i, sc)) {
ConstString mangled_name =
sc.GetFunctionName(Mangled::ePreferMangled);
ConstString demangled_name =
sc.GetFunctionName(Mangled::ePreferDemangled);
// Mangled names on Linux and FreeBSD are of the form:
// _ZN18function_namespace13function_nameEv.
if (strncmp(mangled_name.GetCString(), "_ZN", 3) ||
!strncmp(demangled_name.GetCString(), "(anonymous namespace)",
21)) {
sc_list.Append(sc);
}
}
}
}
}
}
DIEArray die_offsets;
if (name_type_mask & eFunctionNameTypeBase) {
uint32_t num_base = m_function_basename_index.Find(name, die_offsets);
for (uint32_t i = 0; i < num_base; i++) {
DWARFDIE die = info->GetDIE(die_offsets[i]);
if (die) {
if (!DIEInDeclContext(parent_decl_ctx, die))
continue; // The containing decl contexts don't match
// If we get to here, the die is good, and we should add it:
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
if (ResolveFunction(die, include_inlines, sc_list))
resolved_dies.insert(die.GetDIE());
}
}
}
die_offsets.clear();
}
if (name_type_mask & eFunctionNameTypeMethod) {
if (parent_decl_ctx && parent_decl_ctx->IsValid())
return 0; // no methods in namespaces
uint32_t num_base = m_function_method_index.Find(name, die_offsets);
{
for (uint32_t i = 0; i < num_base; i++) {
DWARFDIE die = info->GetDIE(die_offsets[i]);
if (die) {
// If we get to here, the die is good, and we should add it:
if (resolved_dies.find(die.GetDIE()) == resolved_dies.end()) {
if (ResolveFunction(die, include_inlines, sc_list))
resolved_dies.insert(die.GetDIE());
}
}
}
}
die_offsets.clear();
}
if ((name_type_mask & eFunctionNameTypeSelector) &&
(!parent_decl_ctx || !parent_decl_ctx->IsValid())) {
FindFunctions(name, m_function_selector_index, include_inlines, sc_list);
}
}
// Return the number of variable that were appended to the list
const uint32_t num_matches = sc_list.GetSize() - original_size;
if (log && num_matches > 0) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindFunctions (name=\"%s\", "
"name_type_mask=0x%x, include_inlines=%d, append=%u, sc_list) => "
"%u",
name.GetCString(), name_type_mask, include_inlines, append,
num_matches);
}
return num_matches;
}
uint32_t SymbolFileDWARF::FindFunctions(const RegularExpression &regex,
bool include_inlines, bool append,
SymbolContextList &sc_list) {
static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (regex = '%s')",
regex.GetText().str().c_str());
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log,
"SymbolFileDWARF::FindFunctions (regex=\"%s\", append=%u, sc_list)",
regex.GetText().str().c_str(), append);
}
// If we aren't appending the results to this list, then clear the list
if (!append)
sc_list.Clear();
// Remember how many sc_list are in the list before we search in case
// we are appending the results to a variable list.
uint32_t original_size = sc_list.GetSize();
if (m_using_apple_tables) {
if (m_apple_names_ap.get())
FindFunctions(regex, *m_apple_names_ap, include_inlines, sc_list);
} else {
// Index the DWARF if we haven't already
if (!m_indexed)
Index();
FindFunctions(regex, m_function_basename_index, include_inlines, sc_list);
FindFunctions(regex, m_function_fullname_index, include_inlines, sc_list);
}
// Return the number of variable that were appended to the list
return sc_list.GetSize() - original_size;
}
void SymbolFileDWARF::GetMangledNamesForFunction(
const std::string &scope_qualified_name,
std::vector<ConstString> &mangled_names) {
DWARFDebugInfo *info = DebugInfo();
uint32_t num_comp_units = 0;
if (info)
num_comp_units = info->GetNumCompileUnits();
for (uint32_t i = 0; i < num_comp_units; i++) {
DWARFCompileUnit *cu = info->GetCompileUnitAtIndex(i);
if (cu == nullptr)
continue;
SymbolFileDWARFDwo *dwo = cu->GetDwoSymbolFile();
if (dwo)
dwo->GetMangledNamesForFunction(scope_qualified_name, mangled_names);
}
NameToOffsetMap::iterator iter =
m_function_scope_qualified_name_map.find(scope_qualified_name);
if (iter == m_function_scope_qualified_name_map.end())
return;
DIERefSetSP set_sp = (*iter).second;
std::set<DIERef>::iterator set_iter;
for (set_iter = set_sp->begin(); set_iter != set_sp->end(); set_iter++) {
DWARFDIE die = DebugInfo()->GetDIE(*set_iter);
mangled_names.push_back(ConstString(die.GetMangledName()));
}
}
uint32_t SymbolFileDWARF::FindTypes(
const SymbolContext &sc, const ConstString &name,
const CompilerDeclContext *parent_decl_ctx, bool append,
uint32_t max_matches,
llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
TypeMap &types) {
// If we aren't appending the results to this list, then clear the list
if (!append)
types.Clear();
// Make sure we haven't already searched this SymbolFile before...
if (searched_symbol_files.count(this))
return 0;
else
searched_symbol_files.insert(this);
DWARFDebugInfo *info = DebugInfo();
if (info == NULL)
return 0;
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log) {
if (parent_decl_ctx)
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx = "
"%p (\"%s\"), append=%u, max_matches=%u, type_list)",
name.GetCString(), static_cast<const void *>(parent_decl_ctx),
parent_decl_ctx->GetName().AsCString("<NULL>"), append, max_matches);
else
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx = "
"NULL, append=%u, max_matches=%u, type_list)",
name.GetCString(), append, max_matches);
}
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return 0;
DIEArray die_offsets;
if (m_using_apple_tables) {
if (m_apple_types_ap.get()) {
const char *name_cstr = name.GetCString();
m_apple_types_ap->FindByName(name_cstr, die_offsets);
}
} else {
if (!m_indexed)
Index();
m_type_index.Find(name, die_offsets);
}
const size_t num_die_matches = die_offsets.size();
if (num_die_matches) {
const uint32_t initial_types_size = types.GetSize();
for (size_t i = 0; i < num_die_matches; ++i) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = GetDIE(die_ref);
if (die) {
if (!DIEInDeclContext(parent_decl_ctx, die))
continue; // The containing decl contexts don't match
Type *matching_type = ResolveType(die, true, true);
if (matching_type) {
// We found a type pointer, now find the shared pointer form our type
// list
types.InsertUnique(matching_type->shared_from_this());
if (types.GetSize() >= max_matches)
break;
}
} else {
if (m_using_apple_tables) {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (.apple_types "
"accelerator table had bad die 0x%8.8x for '%s')\n",
die_ref.die_offset, name.GetCString());
}
}
}
const uint32_t num_matches = types.GetSize() - initial_types_size;
if (log && num_matches) {
if (parent_decl_ctx) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx "
"= %p (\"%s\"), append=%u, max_matches=%u, type_list) => %u",
name.GetCString(), static_cast<const void *>(parent_decl_ctx),
parent_decl_ctx->GetName().AsCString("<NULL>"), append, max_matches,
num_matches);
} else {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindTypes (sc, name=\"%s\", parent_decl_ctx "
"= NULL, append=%u, max_matches=%u, type_list) => %u",
name.GetCString(), append, max_matches, num_matches);
}
}
return num_matches;
} else {
UpdateExternalModuleListIfNeeded();
for (const auto &pair : m_external_type_modules) {
ModuleSP external_module_sp = pair.second;
if (external_module_sp) {
SymbolVendor *sym_vendor = external_module_sp->GetSymbolVendor();
if (sym_vendor) {
const uint32_t num_external_matches =
sym_vendor->FindTypes(sc, name, parent_decl_ctx, append,
max_matches, searched_symbol_files, types);
if (num_external_matches)
return num_external_matches;
}
}
}
}
return 0;
}
size_t SymbolFileDWARF::FindTypes(const std::vector<CompilerContext> &context,
bool append, TypeMap &types) {
if (!append)
types.Clear();
if (context.empty())
return 0;
DIEArray die_offsets;
ConstString name = context.back().name;
if (!name)
return 0;
if (m_using_apple_tables) {
if (m_apple_types_ap.get()) {
const char *name_cstr = name.GetCString();
m_apple_types_ap->FindByName(name_cstr, die_offsets);
}
} else {
if (!m_indexed)
Index();
m_type_index.Find(name, die_offsets);
}
const size_t num_die_matches = die_offsets.size();
if (num_die_matches) {
size_t num_matches = 0;
for (size_t i = 0; i < num_die_matches; ++i) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = GetDIE(die_ref);
if (die) {
std::vector<CompilerContext> die_context;
die.GetDWOContext(die_context);
if (die_context != context)
continue;
Type *matching_type = ResolveType(die, true, true);
if (matching_type) {
// We found a type pointer, now find the shared pointer form our type
// list
types.InsertUnique(matching_type->shared_from_this());
++num_matches;
}
} else {
if (m_using_apple_tables) {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (.apple_types "
"accelerator table had bad die 0x%8.8x for '%s')\n",
die_ref.die_offset, name.GetCString());
}
}
}
return num_matches;
}
return 0;
}
CompilerDeclContext
SymbolFileDWARF::FindNamespace(const SymbolContext &sc, const ConstString &name,
const CompilerDeclContext *parent_decl_ctx) {
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindNamespace (sc, name=\"%s\")",
name.GetCString());
}
CompilerDeclContext namespace_decl_ctx;
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return namespace_decl_ctx;
DWARFDebugInfo *info = DebugInfo();
if (info) {
DIEArray die_offsets;
// Index if we already haven't to make sure the compile units
// get indexed and make their global DIE index list
if (m_using_apple_tables) {
if (m_apple_namespaces_ap.get()) {
const char *name_cstr = name.GetCString();
m_apple_namespaces_ap->FindByName(name_cstr, die_offsets);
}
} else {
if (!m_indexed)
Index();
m_namespace_index.Find(name, die_offsets);
}
const size_t num_matches = die_offsets.size();
if (num_matches) {
for (size_t i = 0; i < num_matches; ++i) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = GetDIE(die_ref);
if (die) {
if (!DIEInDeclContext(parent_decl_ctx, die))
continue; // The containing decl contexts don't match
DWARFASTParser *dwarf_ast = die.GetDWARFParser();
if (dwarf_ast) {
namespace_decl_ctx = dwarf_ast->GetDeclContextForUIDFromDWARF(die);
if (namespace_decl_ctx)
break;
}
} else {
if (m_using_apple_tables) {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified "
"(.apple_namespaces accelerator table had bad die 0x%8.8x for "
"'%s')\n",
die_ref.die_offset, name.GetCString());
}
}
}
}
}
if (log && namespace_decl_ctx) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindNamespace (sc, name=\"%s\") => "
"CompilerDeclContext(%p/%p) \"%s\"",
name.GetCString(),
static_cast<const void *>(namespace_decl_ctx.GetTypeSystem()),
static_cast<const void *>(namespace_decl_ctx.GetOpaqueDeclContext()),
namespace_decl_ctx.GetName().AsCString("<NULL>"));
}
return namespace_decl_ctx;
}
TypeSP SymbolFileDWARF::GetTypeForDIE(const DWARFDIE &die,
bool resolve_function_context) {
TypeSP type_sp;
if (die) {
Type *type_ptr = GetDIEToType().lookup(die.GetDIE());
if (type_ptr == NULL) {
CompileUnit *lldb_cu = GetCompUnitForDWARFCompUnit(die.GetCU());
assert(lldb_cu);
SymbolContext sc(lldb_cu);
const DWARFDebugInfoEntry *parent_die = die.GetParent().GetDIE();
while (parent_die != nullptr) {
if (parent_die->Tag() == DW_TAG_subprogram)
break;
parent_die = parent_die->GetParent();
}
SymbolContext sc_backup = sc;
if (resolve_function_context && parent_die != nullptr &&
!GetFunction(DWARFDIE(die.GetCU(), parent_die), sc))
sc = sc_backup;
type_sp = ParseType(sc, die, NULL);
} else if (type_ptr != DIE_IS_BEING_PARSED) {
// Grab the existing type from the master types lists
type_sp = type_ptr->shared_from_this();
}
}
return type_sp;
}
DWARFDIE
SymbolFileDWARF::GetDeclContextDIEContainingDIE(const DWARFDIE &orig_die) {
if (orig_die) {
DWARFDIE die = orig_die;
while (die) {
// If this is the original DIE that we are searching for a declaration
// for, then don't look in the cache as we don't want our own decl
// context to be our decl context...
if (orig_die != die) {
switch (die.Tag()) {
case DW_TAG_compile_unit:
case DW_TAG_namespace:
case DW_TAG_structure_type:
case DW_TAG_union_type:
case DW_TAG_class_type:
case DW_TAG_lexical_block:
case DW_TAG_subprogram:
return die;
case DW_TAG_inlined_subroutine: {
DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin);
if (abs_die) {
return abs_die;
}
break;
}
default:
break;
}
}
DWARFDIE spec_die = die.GetReferencedDIE(DW_AT_specification);
if (spec_die) {
DWARFDIE decl_ctx_die = GetDeclContextDIEContainingDIE(spec_die);
if (decl_ctx_die)
return decl_ctx_die;
}
DWARFDIE abs_die = die.GetReferencedDIE(DW_AT_abstract_origin);
if (abs_die) {
DWARFDIE decl_ctx_die = GetDeclContextDIEContainingDIE(abs_die);
if (decl_ctx_die)
return decl_ctx_die;
}
die = die.GetParent();
}
}
return DWARFDIE();
}
Symbol *
SymbolFileDWARF::GetObjCClassSymbol(const ConstString &objc_class_name) {
Symbol *objc_class_symbol = NULL;
if (m_obj_file) {
Symtab *symtab = m_obj_file->GetSymtab();
if (symtab) {
objc_class_symbol = symtab->FindFirstSymbolWithNameAndType(
objc_class_name, eSymbolTypeObjCClass, Symtab::eDebugNo,
Symtab::eVisibilityAny);
}
}
return objc_class_symbol;
}
// Some compilers don't emit the DW_AT_APPLE_objc_complete_type attribute. If
// they don't
// then we can end up looking through all class types for a complete type and
// never find
// the full definition. We need to know if this attribute is supported, so we
// determine
// this here and cache th result. We also need to worry about the debug map
// DWARF file
// if we are doing darwin DWARF in .o file debugging.
bool SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type(
DWARFCompileUnit *cu) {
if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate) {
m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo;
if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type())
m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
else {
DWARFDebugInfo *debug_info = DebugInfo();
const uint32_t num_compile_units = GetNumCompileUnits();
for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) {
DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
if (dwarf_cu != cu &&
dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type()) {
m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
break;
}
}
}
if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolNo &&
GetDebugMapSymfile())
return m_debug_map_symfile->Supports_DW_AT_APPLE_objc_complete_type(this);
}
return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes;
}
// This function can be used when a DIE is found that is a forward declaration
// DIE and we want to try and find a type that has the complete definition.
TypeSP SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE(
const DWARFDIE &die, const ConstString &type_name,
bool must_be_implementation) {
TypeSP type_sp;
if (!type_name || (must_be_implementation && !GetObjCClassSymbol(type_name)))
return type_sp;
DIEArray die_offsets;
if (m_using_apple_tables) {
if (m_apple_types_ap.get()) {
const char *name_cstr = type_name.GetCString();
m_apple_types_ap->FindCompleteObjCClassByName(name_cstr, die_offsets,
must_be_implementation);
}
} else {
if (!m_indexed)
Index();
m_type_index.Find(type_name, die_offsets);
}
const size_t num_matches = die_offsets.size();
if (num_matches) {
for (size_t i = 0; i < num_matches; ++i) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE type_die = GetDIE(die_ref);
if (type_die) {
bool try_resolving_type = false;
// Don't try and resolve the DIE we are looking for with the DIE itself!
if (type_die != die) {
switch (type_die.Tag()) {
case DW_TAG_class_type:
case DW_TAG_structure_type:
try_resolving_type = true;
break;
default:
break;
}
}
if (try_resolving_type) {
if (must_be_implementation &&
type_die.Supports_DW_AT_APPLE_objc_complete_type())
try_resolving_type = type_die.GetAttributeValueAsUnsigned(
DW_AT_APPLE_objc_complete_type, 0);
if (try_resolving_type) {
Type *resolved_type = ResolveType(type_die, false, true);
if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) {
DEBUG_PRINTF("resolved 0x%8.8" PRIx64 " from %s to 0x%8.8" PRIx64
" (cu 0x%8.8" PRIx64 ")\n",
die.GetID(),
m_obj_file->GetFileSpec().GetFilename().AsCString(
"<Unknown>"),
type_die.GetID(), type_cu->GetID());
if (die)
GetDIEToType()[die.GetDIE()] = resolved_type;
type_sp = resolved_type->shared_from_this();
break;
}
}
}
} else {
if (m_using_apple_tables) {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (.apple_types "
"accelerator table had bad die 0x%8.8x for '%s')\n",
die_ref.die_offset, type_name.GetCString());
}
}
}
}
return type_sp;
}
//----------------------------------------------------------------------
// This function helps to ensure that the declaration contexts match for
// two different DIEs. Often times debug information will refer to a
// forward declaration of a type (the equivalent of "struct my_struct;".
// There will often be a declaration of that type elsewhere that has the
// full definition. When we go looking for the full type "my_struct", we
// will find one or more matches in the accelerator tables and we will
// then need to make sure the type was in the same declaration context
// as the original DIE. This function can efficiently compare two DIEs
// and will return true when the declaration context matches, and false
// when they don't.
//----------------------------------------------------------------------
bool SymbolFileDWARF::DIEDeclContextsMatch(const DWARFDIE &die1,
const DWARFDIE &die2) {
if (die1 == die2)
return true;
DWARFDIECollection decl_ctx_1;
DWARFDIECollection decl_ctx_2;
// The declaration DIE stack is a stack of the declaration context
// DIEs all the way back to the compile unit. If a type "T" is
// declared inside a class "B", and class "B" is declared inside
// a class "A" and class "A" is in a namespace "lldb", and the
// namespace is in a compile unit, there will be a stack of DIEs:
//
// [0] DW_TAG_class_type for "B"
// [1] DW_TAG_class_type for "A"
// [2] DW_TAG_namespace for "lldb"
// [3] DW_TAG_compile_unit for the source file.
//
// We grab both contexts and make sure that everything matches
// all the way back to the compiler unit.
// First lets grab the decl contexts for both DIEs
die1.GetDeclContextDIEs(decl_ctx_1);
die2.GetDeclContextDIEs(decl_ctx_2);
// Make sure the context arrays have the same size, otherwise
// we are done
const size_t count1 = decl_ctx_1.Size();
const size_t count2 = decl_ctx_2.Size();
if (count1 != count2)
return false;
// Make sure the DW_TAG values match all the way back up the
// compile unit. If they don't, then we are done.
DWARFDIE decl_ctx_die1;
DWARFDIE decl_ctx_die2;
size_t i;
for (i = 0; i < count1; i++) {
decl_ctx_die1 = decl_ctx_1.GetDIEAtIndex(i);
decl_ctx_die2 = decl_ctx_2.GetDIEAtIndex(i);
if (decl_ctx_die1.Tag() != decl_ctx_die2.Tag())
return false;
}
#if defined LLDB_CONFIGURATION_DEBUG
// Make sure the top item in the decl context die array is always
// DW_TAG_compile_unit. If it isn't then something went wrong in
// the DWARFDIE::GetDeclContextDIEs() function...
assert(decl_ctx_1.GetDIEAtIndex(count1 - 1).Tag() == DW_TAG_compile_unit);
#endif
// Always skip the compile unit when comparing by only iterating up to
// "count - 1". Here we compare the names as we go.
for (i = 0; i < count1 - 1; i++) {
decl_ctx_die1 = decl_ctx_1.GetDIEAtIndex(i);
decl_ctx_die2 = decl_ctx_2.GetDIEAtIndex(i);
const char *name1 = decl_ctx_die1.GetName();
const char *name2 = decl_ctx_die2.GetName();
// If the string was from a DW_FORM_strp, then the pointer will often
// be the same!
if (name1 == name2)
continue;
// Name pointers are not equal, so only compare the strings
// if both are not NULL.
if (name1 && name2) {
// If the strings don't compare, we are done...
if (strcmp(name1, name2) != 0)
return false;
} else {
// One name was NULL while the other wasn't
return false;
}
}
// We made it through all of the checks and the declaration contexts
// are equal.
return true;
}
TypeSP SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(
const DWARFDeclContext &dwarf_decl_ctx) {
TypeSP type_sp;
const uint32_t dwarf_decl_ctx_count = dwarf_decl_ctx.GetSize();
if (dwarf_decl_ctx_count > 0) {
const ConstString type_name(dwarf_decl_ctx[0].name);
const dw_tag_t tag = dwarf_decl_ctx[0].tag;
if (type_name) {
Log *log(LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION |
DWARF_LOG_LOOKUPS));
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%"
"s, qualified-name='%s')",
DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
dwarf_decl_ctx.GetQualifiedName());
}
DIEArray die_offsets;
if (m_using_apple_tables) {
if (m_apple_types_ap.get()) {
const bool has_tag =
m_apple_types_ap->GetHeader().header_data.ContainsAtom(
DWARFMappedHash::eAtomTypeTag);
const bool has_qualified_name_hash =
m_apple_types_ap->GetHeader().header_data.ContainsAtom(
DWARFMappedHash::eAtomTypeQualNameHash);
if (has_tag && has_qualified_name_hash) {
const char *qualified_name = dwarf_decl_ctx.GetQualifiedName();
const uint32_t qualified_name_hash =
MappedHash::HashStringUsingDJB(qualified_name);
if (log)
GetObjectFile()->GetModule()->LogMessage(
log, "FindByNameAndTagAndQualifiedNameHash()");
m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash(
type_name.GetCString(), tag, qualified_name_hash, die_offsets);
} else if (has_tag) {
if (log)
GetObjectFile()->GetModule()->LogMessage(log,
"FindByNameAndTag()");
m_apple_types_ap->FindByNameAndTag(type_name.GetCString(), tag,
die_offsets);
} else {
m_apple_types_ap->FindByName(type_name.GetCString(), die_offsets);
}
}
} else {
if (!m_indexed)
Index();
m_type_index.Find(type_name, die_offsets);
}
const size_t num_matches = die_offsets.size();
// Get the type system that we are looking to find a type for. We will use
// this
// to ensure any matches we find are in a language that this type system
// supports
const LanguageType language = dwarf_decl_ctx.GetLanguage();
TypeSystem *type_system = (language == eLanguageTypeUnknown)
? nullptr
: GetTypeSystemForLanguage(language);
if (num_matches) {
for (size_t i = 0; i < num_matches; ++i) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE type_die = GetDIE(die_ref);
if (type_die) {
// Make sure type_die's langauge matches the type system we are
// looking for.
// We don't want to find a "Foo" type from Java if we are looking
// for a "Foo"
// type for C, C++, ObjC, or ObjC++.
if (type_system &&
!type_system->SupportsLanguage(type_die.GetLanguage()))
continue;
bool try_resolving_type = false;
// Don't try and resolve the DIE we are looking for with the DIE
// itself!
const dw_tag_t type_tag = type_die.Tag();
// Make sure the tags match
if (type_tag == tag) {
// The tags match, lets try resolving this type
try_resolving_type = true;
} else {
// The tags don't match, but we need to watch our for a
// forward declaration for a struct and ("struct foo")
// ends up being a class ("class foo { ... };") or
// vice versa.
switch (type_tag) {
case DW_TAG_class_type:
// We had a "class foo", see if we ended up with a "struct foo {
// ... };"
try_resolving_type = (tag == DW_TAG_structure_type);
break;
case DW_TAG_structure_type:
// We had a "struct foo", see if we ended up with a "class foo {
// ... };"
try_resolving_type = (tag == DW_TAG_class_type);
break;
default:
// Tags don't match, don't event try to resolve
// using this type whose name matches....
break;
}
}
if (try_resolving_type) {
DWARFDeclContext type_dwarf_decl_ctx;
type_die.GetDWARFDeclContext(type_dwarf_decl_ctx);
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::"
"FindDefinitionTypeForDWARFDeclContext(tag=%s, "
"qualified-name='%s') trying die=0x%8.8x (%s)",
DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
dwarf_decl_ctx.GetQualifiedName(), type_die.GetOffset(),
type_dwarf_decl_ctx.GetQualifiedName());
}
// Make sure the decl contexts match all the way up
if (dwarf_decl_ctx == type_dwarf_decl_ctx) {
Type *resolved_type = ResolveType(type_die, false);
if (resolved_type && resolved_type != DIE_IS_BEING_PARSED) {
type_sp = resolved_type->shared_from_this();
break;
}
}
} else {
if (log) {
std::string qualified_name;
type_die.GetQualifiedName(qualified_name);
GetObjectFile()->GetModule()->LogMessage(
log, "SymbolFileDWARF::"
"FindDefinitionTypeForDWARFDeclContext(tag=%s, "
"qualified-name='%s') ignoring die=0x%8.8x (%s)",
DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
dwarf_decl_ctx.GetQualifiedName(), type_die.GetOffset(),
qualified_name.c_str());
}
}
} else {
if (m_using_apple_tables) {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified (.apple_types "
"accelerator table had bad die 0x%8.8x for '%s')\n",
die_ref.die_offset, type_name.GetCString());
}
}
}
}
}
}
return type_sp;
}
TypeSP SymbolFileDWARF::ParseType(const SymbolContext &sc, const DWARFDIE &die,
bool *type_is_new_ptr) {
TypeSP type_sp;
if (die) {
TypeSystem *type_system =
GetTypeSystemForLanguage(die.GetCU()->GetLanguageType());
if (type_system) {
DWARFASTParser *dwarf_ast = type_system->GetDWARFParser();
if (dwarf_ast) {
Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO);
type_sp = dwarf_ast->ParseTypeFromDWARF(sc, die, log, type_is_new_ptr);
if (type_sp) {
TypeList *type_list = GetTypeList();
if (type_list)
type_list->Insert(type_sp);
if (die.Tag() == DW_TAG_subprogram) {
DIERef die_ref = die.GetDIERef();
std::string scope_qualified_name(GetDeclContextForUID(die.GetID())
.GetScopeQualifiedName()
.AsCString(""));
if (scope_qualified_name.size()) {
NameToOffsetMap::iterator iter =
m_function_scope_qualified_name_map.find(
scope_qualified_name);
if (iter != m_function_scope_qualified_name_map.end())
(*iter).second->insert(die_ref);
else {
DIERefSetSP new_set(new std::set<DIERef>);
new_set->insert(die_ref);
m_function_scope_qualified_name_map.emplace(
std::make_pair(scope_qualified_name, new_set));
}
}
}
}
}
}
}
return type_sp;
}
size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc,
const DWARFDIE &orig_die,
bool parse_siblings, bool parse_children) {
size_t types_added = 0;
DWARFDIE die = orig_die;
while (die) {
bool type_is_new = false;
if (ParseType(sc, die, &type_is_new).get()) {
if (type_is_new)
++types_added;
}
if (parse_children && die.HasChildren()) {
if (die.Tag() == DW_TAG_subprogram) {
SymbolContext child_sc(sc);
child_sc.function = sc.comp_unit->FindFunctionByUID(die.GetID()).get();
types_added += ParseTypes(child_sc, die.GetFirstChild(), true, true);
} else
types_added += ParseTypes(sc, die.GetFirstChild(), true, true);
}
if (parse_siblings)
die = die.GetSibling();
else
die.Clear();
}
return types_added;
}
size_t SymbolFileDWARF::ParseFunctionBlocks(const SymbolContext &sc) {
assert(sc.comp_unit && sc.function);
size_t functions_added = 0;
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu) {
const dw_offset_t function_die_offset = sc.function->GetID();
DWARFDIE function_die = dwarf_cu->GetDIE(function_die_offset);
if (function_die) {
ParseFunctionBlocks(sc, &sc.function->GetBlock(false), function_die,
LLDB_INVALID_ADDRESS, 0);
}
}
return functions_added;
}
size_t SymbolFileDWARF::ParseTypes(const SymbolContext &sc) {
// At least a compile unit must be valid
assert(sc.comp_unit);
size_t types_added = 0;
DWARFCompileUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu) {
if (sc.function) {
dw_offset_t function_die_offset = sc.function->GetID();
DWARFDIE func_die = dwarf_cu->GetDIE(function_die_offset);
if (func_die && func_die.HasChildren()) {
types_added = ParseTypes(sc, func_die.GetFirstChild(), true, true);
}
} else {
DWARFDIE dwarf_cu_die = dwarf_cu->DIE();
if (dwarf_cu_die && dwarf_cu_die.HasChildren()) {
types_added = ParseTypes(sc, dwarf_cu_die.GetFirstChild(), true, true);
}
}
}
return types_added;
}
size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) {
if (sc.comp_unit != NULL) {
DWARFDebugInfo *info = DebugInfo();
if (info == NULL)
return 0;
if (sc.function) {
DWARFDIE function_die = info->GetDIE(DIERef(sc.function->GetID(), this));
const dw_addr_t func_lo_pc = function_die.GetAttributeValueAsAddress(
DW_AT_low_pc, LLDB_INVALID_ADDRESS);
if (func_lo_pc != LLDB_INVALID_ADDRESS) {
const size_t num_variables = ParseVariables(
sc, function_die.GetFirstChild(), func_lo_pc, true, true);
// Let all blocks know they have parse all their variables
sc.function->GetBlock(false).SetDidParseVariables(true, true);
return num_variables;
}
} else if (sc.comp_unit) {
DWARFCompileUnit *dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID());
if (dwarf_cu == NULL)
return 0;
uint32_t vars_added = 0;
VariableListSP variables(sc.comp_unit->GetVariableList(false));
if (variables.get() == NULL) {
variables.reset(new VariableList());
sc.comp_unit->SetVariableList(variables);
DIEArray die_offsets;
if (m_using_apple_tables) {
if (m_apple_names_ap.get()) {
DWARFMappedHash::DIEInfoArray hash_data_array;
if (m_apple_names_ap->AppendAllDIEsInRange(
dwarf_cu->GetOffset(), dwarf_cu->GetNextCompileUnitOffset(),
hash_data_array)) {
DWARFMappedHash::ExtractDIEArray(hash_data_array, die_offsets);
}
}
} else {
// Index if we already haven't to make sure the compile units
// get indexed and make their global DIE index list
if (!m_indexed)
Index();
m_global_index.FindAllEntriesForCompileUnit(dwarf_cu->GetOffset(),
die_offsets);
}
const size_t num_matches = die_offsets.size();
if (num_matches) {
for (size_t i = 0; i < num_matches; ++i) {
const DIERef &die_ref = die_offsets[i];
DWARFDIE die = GetDIE(die_ref);
if (die) {
VariableSP var_sp(
ParseVariableDIE(sc, die, LLDB_INVALID_ADDRESS));
if (var_sp) {
variables->AddVariableIfUnique(var_sp);
++vars_added;
}
} else {
if (m_using_apple_tables) {
GetObjectFile()->GetModule()->ReportErrorIfModifyDetected(
"the DWARF debug information has been modified "
"(.apple_names accelerator table had bad die 0x%8.8x)\n",
die_ref.die_offset);
}
}
}
}
}
return vars_added;
}
}
return 0;
}
VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
const DWARFDIE &die,
const lldb::addr_t func_low_pc) {
if (die.GetDWARF() != this)
return die.GetDWARF()->ParseVariableDIE(sc, die, func_low_pc);
VariableSP var_sp;
if (!die)
return var_sp;
var_sp = GetDIEToVariable()[die.GetDIE()];
if (var_sp)
return var_sp; // Already been parsed!
const dw_tag_t tag = die.Tag();
ModuleSP module = GetObjectFile()->GetModule();
if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) ||
(tag == DW_TAG_formal_parameter && sc.function)) {
DWARFAttributes attributes;
const size_t num_attributes = die.GetAttributes(attributes);
DWARFDIE spec_die;
if (num_attributes > 0) {
const char *name = NULL;
const char *mangled = NULL;
Declaration decl;
uint32_t i;
DWARFFormValue type_die_form;
DWARFExpression location(die.GetCU());
bool is_external = false;
bool is_artificial = false;
bool location_is_const_value_data = false;
bool has_explicit_location = false;
DWARFFormValue const_value;
Variable::RangeList scope_ranges;
// AccessType accessibility = eAccessNone;
for (i = 0; i < num_attributes; ++i) {
dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
if (attributes.ExtractFormValueAtIndex(i, form_value)) {
switch (attr) {
case DW_AT_decl_file:
decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(
form_value.Unsigned()));
break;
case DW_AT_decl_line:
decl.SetLine(form_value.Unsigned());
break;
case DW_AT_decl_column:
decl.SetColumn(form_value.Unsigned());
break;
case DW_AT_name:
name = form_value.AsCString();
break;
case DW_AT_linkage_name:
case DW_AT_MIPS_linkage_name:
mangled = form_value.AsCString();
break;
case DW_AT_type:
type_die_form = form_value;
break;
case DW_AT_external:
is_external = form_value.Boolean();
break;
case DW_AT_const_value:
// If we have already found a DW_AT_location attribute, ignore this
// attribute.
if (!has_explicit_location) {
location_is_const_value_data = true;
// The constant value will be either a block, a data value or a
// string.
const DWARFDataExtractor &debug_info_data = get_debug_info_data();
if (DWARFFormValue::IsBlockForm(form_value.Form())) {
// Retrieve the value as a block expression.
uint32_t block_offset =
form_value.BlockData() - debug_info_data.GetDataStart();
uint32_t block_length = form_value.Unsigned();
location.CopyOpcodeData(module, debug_info_data, block_offset,
block_length);
} else if (DWARFFormValue::IsDataForm(form_value.Form())) {
// Retrieve the value as a data expression.
DWARFFormValue::FixedFormSizes fixed_form_sizes =
DWARFFormValue::GetFixedFormSizesForAddressSize(
attributes.CompileUnitAtIndex(i)->GetAddressByteSize(),
attributes.CompileUnitAtIndex(i)->IsDWARF64());
uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
uint32_t data_length =
fixed_form_sizes.GetSize(form_value.Form());
if (data_length == 0) {
const uint8_t *data_pointer = form_value.BlockData();
if (data_pointer) {
form_value.Unsigned();
} else if (DWARFFormValue::IsDataForm(form_value.Form())) {
// we need to get the byte size of the type later after we
// create the variable
const_value = form_value;
}
} else
location.CopyOpcodeData(module, debug_info_data, data_offset,
data_length);
} else {
// Retrieve the value as a string expression.
if (form_value.Form() == DW_FORM_strp) {
DWARFFormValue::FixedFormSizes fixed_form_sizes =
DWARFFormValue::GetFixedFormSizesForAddressSize(
attributes.CompileUnitAtIndex(i)
->GetAddressByteSize(),
attributes.CompileUnitAtIndex(i)->IsDWARF64());
uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
uint32_t data_length =
fixed_form_sizes.GetSize(form_value.Form());
location.CopyOpcodeData(module, debug_info_data, data_offset,
data_length);
} else {
const char *str = form_value.AsCString();
uint32_t string_offset =
str - (const char *)debug_info_data.GetDataStart();
uint32_t string_length = strlen(str) + 1;
location.CopyOpcodeData(module, debug_info_data,
string_offset, string_length);
}
}
}
break;
case DW_AT_location: {
location_is_const_value_data = false;
has_explicit_location = true;
if (DWARFFormValue::IsBlockForm(form_value.Form())) {
const DWARFDataExtractor &debug_info_data = get_debug_info_data();
uint32_t block_offset =
form_value.BlockData() - debug_info_data.GetDataStart();
uint32_t block_length = form_value.Unsigned();
location.CopyOpcodeData(module, get_debug_info_data(),
block_offset, block_length);
} else {
const DWARFDataExtractor &debug_loc_data = get_debug_loc_data();
const dw_offset_t debug_loc_offset = form_value.Unsigned();
size_t loc_list_length = DWARFExpression::LocationListSize(
die.GetCU(), debug_loc_data, debug_loc_offset);
if (loc_list_length > 0) {
location.CopyOpcodeData(module, debug_loc_data,
debug_loc_offset, loc_list_length);
assert(func_low_pc != LLDB_INVALID_ADDRESS);
location.SetLocationListSlide(
func_low_pc -
attributes.CompileUnitAtIndex(i)->GetBaseAddress());
}
}
} break;
case DW_AT_specification:
spec_die = GetDIE(DIERef(form_value));
break;
case DW_AT_start_scope: {
if (form_value.Form() == DW_FORM_sec_offset) {
DWARFRangeList dwarf_scope_ranges;
const DWARFDebugRanges *debug_ranges = DebugRanges();
debug_ranges->FindRanges(die.GetCU()->GetRangesBase(),
form_value.Unsigned(),
dwarf_scope_ranges);
// All DW_AT_start_scope are relative to the base address of the
// compile unit. We add the compile unit base address to make
// sure all the addresses are properly fixed up.
for (size_t i = 0, count = dwarf_scope_ranges.GetSize();
i < count; ++i) {
const DWARFRangeList::Entry &range =
dwarf_scope_ranges.GetEntryRef(i);
scope_ranges.Append(range.GetRangeBase() +
die.GetCU()->GetBaseAddress(),
range.GetByteSize());
}
} else {
// TODO: Handle the case when DW_AT_start_scope have form
// constant. The
// dwarf spec is a bit ambiguous about what is the expected
// behavior in
// case the enclosing block have a non coninious address range and
// the
// DW_AT_start_scope entry have a form constant.
GetObjectFile()->GetModule()->ReportWarning(
"0x%8.8" PRIx64
": DW_AT_start_scope has unsupported form type (0x%x)\n",
die.GetID(), form_value.Form());
}
scope_ranges.Sort();
scope_ranges.CombineConsecutiveRanges();
} break;
case DW_AT_artificial:
is_artificial = form_value.Boolean();
break;
case DW_AT_accessibility:
break; // accessibility =
// DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
case DW_AT_declaration:
case DW_AT_description:
case DW_AT_endianity:
case DW_AT_segment:
case DW_AT_visibility:
default:
case DW_AT_abstract_origin:
case DW_AT_sibling:
break;
}
}
}
const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die);
const dw_tag_t parent_tag = die.GetParent().Tag();
bool is_static_member =
parent_tag == DW_TAG_compile_unit &&
(parent_context_die.Tag() == DW_TAG_class_type ||
parent_context_die.Tag() == DW_TAG_structure_type);
ValueType scope = eValueTypeInvalid;
const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
SymbolContextScope *symbol_context_scope = NULL;
bool has_explicit_mangled = mangled != nullptr;
if (!mangled) {
// LLDB relies on the mangled name (DW_TAG_linkage_name or
// DW_AT_MIPS_linkage_name) to
// generate fully qualified names of global variables with commands like
// "frame var j".
// For example, if j were an int variable holding a value 4 and declared
// in a namespace
// B which in turn is contained in a namespace A, the command "frame var
// j" returns
// "(int) A::B::j = 4". If the compiler does not emit a linkage name, we
// should be able
// to generate a fully qualified name from the declaration context.
if (parent_tag == DW_TAG_compile_unit &&
Language::LanguageIsCPlusPlus(die.GetLanguage())) {
DWARFDeclContext decl_ctx;
die.GetDWARFDeclContext(decl_ctx);
mangled = decl_ctx.GetQualifiedNameAsConstString().GetCString();
}
}
if (tag == DW_TAG_formal_parameter)
scope = eValueTypeVariableArgument;
else {
// DWARF doesn't specify if a DW_TAG_variable is a local, global
// or static variable, so we have to do a little digging:
// 1) DW_AT_linkage_name implies static lifetime (but may be missing)
// 2) An empty DW_AT_location is an (optimized-out) static lifetime var.
// 3) DW_AT_location containing a DW_OP_addr implies static lifetime.
// Clang likes to combine small global variables into the same symbol
// with locations like: DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus
// so we need to look through the whole expression.
bool is_static_lifetime =
has_explicit_mangled ||
(has_explicit_location && !location.IsValid());
// Check if the location has a DW_OP_addr with any address value...
lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS;
if (!location_is_const_value_data) {
bool op_error = false;
location_DW_OP_addr = location.GetLocation_DW_OP_addr(0, op_error);
if (op_error) {
StreamString strm;
location.DumpLocationForAddress(&strm, eDescriptionLevelFull, 0, 0,
NULL);
GetObjectFile()->GetModule()->ReportError(
"0x%8.8x: %s has an invalid location: %s", die.GetOffset(),
die.GetTagAsCString(), strm.GetData());
}
if (location_DW_OP_addr != LLDB_INVALID_ADDRESS)
is_static_lifetime = true;
}
SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
if (is_static_lifetime) {
if (is_external)
scope = eValueTypeVariableGlobal;
else
scope = eValueTypeVariableStatic;
if (debug_map_symfile) {
// When leaving the DWARF in the .o files on darwin,
// when we have a global variable that wasn't initialized,
// the .o file might not have allocated a virtual
// address for the global variable. In this case it will
// have created a symbol for the global variable
// that is undefined/data and external and the value will
// be the byte size of the variable. When we do the
// address map in SymbolFileDWARFDebugMap we rely on
// having an address, we need to do some magic here
// so we can get the correct address for our global
// variable. The address for all of these entries
// will be zero, and there will be an undefined symbol
// in this object file, and the executable will have
// a matching symbol with a good address. So here we
// dig up the correct address and replace it in the
// location for the variable, and set the variable's
// symbol context scope to be that of the main executable
// so the file address will resolve correctly.
bool linked_oso_file_addr = false;
if (is_external && location_DW_OP_addr == 0) {
// we have a possible uninitialized extern global
ConstString const_name(mangled ? mangled : name);
ObjectFile *debug_map_objfile =
debug_map_symfile->GetObjectFile();
if (debug_map_objfile) {
Symtab *debug_map_symtab = debug_map_objfile->GetSymtab();
if (debug_map_symtab) {
Symbol *exe_symbol =
debug_map_symtab->FindFirstSymbolWithNameAndType(
const_name, eSymbolTypeData, Symtab::eDebugYes,
Symtab::eVisibilityExtern);
if (exe_symbol) {
if (exe_symbol->ValueIsAddress()) {
const addr_t exe_file_addr =
exe_symbol->GetAddressRef().GetFileAddress();
if (exe_file_addr != LLDB_INVALID_ADDRESS) {
if (location.Update_DW_OP_addr(exe_file_addr)) {
linked_oso_file_addr = true;
symbol_context_scope = exe_symbol;
}
}
}
}
}
}
}
if (!linked_oso_file_addr) {
// The DW_OP_addr is not zero, but it contains a .o file address
// which
// needs to be linked up correctly.
const lldb::addr_t exe_file_addr =
debug_map_symfile->LinkOSOFileAddress(this,
location_DW_OP_addr);
if (exe_file_addr != LLDB_INVALID_ADDRESS) {
// Update the file address for this variable
location.Update_DW_OP_addr(exe_file_addr);
} else {
// Variable didn't make it into the final executable
return var_sp;
}
}
}
} else {
if (location_is_const_value_data)
scope = eValueTypeVariableStatic;
else {
scope = eValueTypeVariableLocal;
if (debug_map_symfile) {
// We need to check for TLS addresses that we need to fixup
if (location.ContainsThreadLocalStorage()) {
location.LinkThreadLocalStorage(
debug_map_symfile->GetObjectFile()->GetModule(),
[this, debug_map_symfile](
lldb::addr_t unlinked_file_addr) -> lldb::addr_t {
return debug_map_symfile->LinkOSOFileAddress(
this, unlinked_file_addr);
});
scope = eValueTypeVariableThreadLocal;
}
}
}
}
}
if (symbol_context_scope == NULL) {
switch (parent_tag) {
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_lexical_block:
if (sc.function) {
symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(
sc_parent_die.GetID());
if (symbol_context_scope == NULL)
symbol_context_scope = sc.function;
}
break;
default:
symbol_context_scope = sc.comp_unit;
break;
}
}
if (symbol_context_scope) {
SymbolFileTypeSP type_sp(
new SymbolFileType(*this, DIERef(type_die_form).GetUID(this)));
if (const_value.Form() && type_sp && type_sp->GetType())
location.CopyOpcodeData(const_value.Unsigned(),
type_sp->GetType()->GetByteSize(),
die.GetCU()->GetAddressByteSize());
var_sp.reset(new Variable(die.GetID(), name, mangled, type_sp, scope,
symbol_context_scope, scope_ranges, &decl,
location, is_external, is_artificial,
is_static_member));
var_sp->SetLocationIsConstantValueData(location_is_const_value_data);
} else {
// Not ready to parse this variable yet. It might be a global
// or static variable that is in a function scope and the function
// in the symbol context wasn't filled in yet
return var_sp;
}
}
// Cache var_sp even if NULL (the variable was just a specification or
// was missing vital information to be able to be displayed in the debugger
// (missing location due to optimization, etc)) so we don't re-parse
// this DIE over and over later...
GetDIEToVariable()[die.GetDIE()] = var_sp;
if (spec_die)
GetDIEToVariable()[spec_die.GetDIE()] = var_sp;
}
return var_sp;
}
DWARFDIE
SymbolFileDWARF::FindBlockContainingSpecification(
const DIERef &func_die_ref, dw_offset_t spec_block_die_offset) {
// Give the concrete function die specified by "func_die_offset", find the
// concrete block whose DW_AT_specification or DW_AT_abstract_origin points
// to "spec_block_die_offset"
return FindBlockContainingSpecification(DebugInfo()->GetDIE(func_die_ref),
spec_block_die_offset);
}
DWARFDIE
SymbolFileDWARF::FindBlockContainingSpecification(
const DWARFDIE &die, dw_offset_t spec_block_die_offset) {
if (die) {
switch (die.Tag()) {
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_lexical_block: {
if (die.GetAttributeValueAsReference(
DW_AT_specification, DW_INVALID_OFFSET) == spec_block_die_offset)
return die;
if (die.GetAttributeValueAsReference(DW_AT_abstract_origin,
DW_INVALID_OFFSET) ==
spec_block_die_offset)
return die;
} break;
}
// Give the concrete function die specified by "func_die_offset", find the
// concrete block whose DW_AT_specification or DW_AT_abstract_origin points
// to "spec_block_die_offset"
for (DWARFDIE child_die = die.GetFirstChild(); child_die;
child_die = child_die.GetSibling()) {
DWARFDIE result_die =
FindBlockContainingSpecification(child_die, spec_block_die_offset);
if (result_die)
return result_die;
}
}
return DWARFDIE();
}
size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc,
const DWARFDIE &orig_die,
const lldb::addr_t func_low_pc,
bool parse_siblings, bool parse_children,
VariableList *cc_variable_list) {
if (!orig_die)
return 0;
VariableListSP variable_list_sp;
size_t vars_added = 0;
DWARFDIE die = orig_die;
while (die) {
dw_tag_t tag = die.Tag();
// Check to see if we have already parsed this variable or constant?
VariableSP var_sp = GetDIEToVariable()[die.GetDIE()];
if (var_sp) {
if (cc_variable_list)
cc_variable_list->AddVariableIfUnique(var_sp);
} else {
// We haven't already parsed it, lets do that now.
if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) ||
(tag == DW_TAG_formal_parameter && sc.function)) {
if (variable_list_sp.get() == NULL) {
DWARFDIE sc_parent_die = GetParentSymbolContextDIE(orig_die);
dw_tag_t parent_tag = sc_parent_die.Tag();
switch (parent_tag) {
case DW_TAG_compile_unit:
if (sc.comp_unit != NULL) {
variable_list_sp = sc.comp_unit->GetVariableList(false);
if (variable_list_sp.get() == NULL) {
variable_list_sp.reset(new VariableList());
sc.comp_unit->SetVariableList(variable_list_sp);
}
} else {
GetObjectFile()->GetModule()->ReportError(
"parent 0x%8.8" PRIx64 " %s with no valid compile unit in "
"symbol context for 0x%8.8" PRIx64
" %s.\n",
sc_parent_die.GetID(), sc_parent_die.GetTagAsCString(),
orig_die.GetID(), orig_die.GetTagAsCString());
}
break;
case DW_TAG_subprogram:
case DW_TAG_inlined_subroutine:
case DW_TAG_lexical_block:
if (sc.function != NULL) {
// Check to see if we already have parsed the variables for the
// given scope
Block *block = sc.function->GetBlock(true).FindBlockByID(
sc_parent_die.GetID());
if (block == NULL) {
// This must be a specification or abstract origin with
// a concrete block counterpart in the current function. We need
// to find the concrete block so we can correctly add the
// variable to it
const DWARFDIE concrete_block_die =
FindBlockContainingSpecification(
DIERef(sc.function->GetID(), this),
sc_parent_die.GetOffset());
if (concrete_block_die)
block = sc.function->GetBlock(true).FindBlockByID(
concrete_block_die.GetID());
}
if (block != NULL) {
const bool can_create = false;
variable_list_sp = block->GetBlockVariableList(can_create);
if (variable_list_sp.get() == NULL) {
variable_list_sp.reset(new VariableList());
block->SetVariableList(variable_list_sp);
}
}
}
break;
default:
GetObjectFile()->GetModule()->ReportError(
"didn't find appropriate parent DIE for variable list for "
"0x%8.8" PRIx64 " %s.\n",
orig_die.GetID(), orig_die.GetTagAsCString());
break;
}
}
if (variable_list_sp) {
VariableSP var_sp(ParseVariableDIE(sc, die, func_low_pc));
if (var_sp) {
variable_list_sp->AddVariableIfUnique(var_sp);
if (cc_variable_list)
cc_variable_list->AddVariableIfUnique(var_sp);
++vars_added;
}
}
}
}
bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram);
if (!skip_children && parse_children && die.HasChildren()) {
vars_added += ParseVariables(sc, die.GetFirstChild(), func_low_pc, true,
true, cc_variable_list);
}
if (parse_siblings)
die = die.GetSibling();
else
die.Clear();
}
return vars_added;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
ConstString SymbolFileDWARF::GetPluginName() { return GetPluginNameStatic(); }
uint32_t SymbolFileDWARF::GetPluginVersion() { return 1; }
void SymbolFileDWARF::DumpIndexes() {
StreamFile s(stdout, false);
s.Printf(
"DWARF index for (%s) '%s':",
GetObjectFile()->GetModule()->GetArchitecture().GetArchitectureName(),
GetObjectFile()->GetFileSpec().GetPath().c_str());
s.Printf("\nFunction basenames:\n");
m_function_basename_index.Dump(&s);
s.Printf("\nFunction fullnames:\n");
m_function_fullname_index.Dump(&s);
s.Printf("\nFunction methods:\n");
m_function_method_index.Dump(&s);
s.Printf("\nFunction selectors:\n");
m_function_selector_index.Dump(&s);
s.Printf("\nObjective C class selectors:\n");
m_objc_class_selectors_index.Dump(&s);
s.Printf("\nGlobals and statics:\n");
m_global_index.Dump(&s);
s.Printf("\nTypes:\n");
m_type_index.Dump(&s);
s.Printf("\nNamespaces:\n");
m_namespace_index.Dump(&s);
}
SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() {
if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired()) {
lldb::ModuleSP module_sp(m_debug_map_module_wp.lock());
if (module_sp) {
SymbolVendor *sym_vendor = module_sp->GetSymbolVendor();
if (sym_vendor)
m_debug_map_symfile =
(SymbolFileDWARFDebugMap *)sym_vendor->GetSymbolFile();
}
}
return m_debug_map_symfile;
}
DWARFExpression::LocationListFormat
SymbolFileDWARF::GetLocationListFormat() const {
return DWARFExpression::RegularLocationList;
}
SymbolFileDWARFDwp *SymbolFileDWARF::GetDwpSymbolFile() {
llvm::call_once(m_dwp_symfile_once_flag, [this]() {
ModuleSpec module_spec;
module_spec.GetFileSpec() = m_obj_file->GetFileSpec();
module_spec.GetSymbolFileSpec() =
FileSpec(m_obj_file->GetFileSpec().GetPath() + ".dwp", false);
FileSpec dwp_filespec = Symbols::LocateExecutableSymbolFile(module_spec);
if (dwp_filespec.Exists()) {
m_dwp_symfile = SymbolFileDWARFDwp::Create(GetObjectFile()->GetModule(),
dwp_filespec);
}
});
return m_dwp_symfile.get();
}