llvm-project/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

3780 lines
137 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/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/Scalar.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.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 "lldb/Target/Language.h"
#include "AppleDWARFIndex.h"
#include "DWARFASTParser.h"
#include "DWARFASTParserClang.h"
#include "DWARFDIECollection.h"
#include "DWARFDebugAbbrev.h"
#include "DWARFDebugAranges.h"
#include "DWARFDebugInfo.h"
#include "DWARFDebugLine.h"
#include "DWARFDebugMacro.h"
#include "DWARFDebugRanges.h"
#include "DWARFDeclContext.h"
#include "DWARFFormValue.h"
#include "DWARFUnit.h"
#include "DebugNamesDWARFIndex.h"
#include "LogChannelDWARF.h"
#include "ManualDWARFIndex.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."},
{"ignore-file-indexes", OptionValue::eTypeBoolean, true, 0, nullptr,
nullptr,
"Ignore indexes present in the object files and always index DWARF "
"manually."},
{nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr},
};
enum {
ePropertySymLinkPaths,
ePropertyIgnoreIndexes,
};
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();
}
bool IgnoreFileIndexes() const {
return m_collection_sp->GetPropertyAtIndexAsBoolean(
nullptr, ePropertyIgnoreIndexes, false);
}
};
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 FileSpec resolveCompDir(const char *path_from_dwarf) {
if (!path_from_dwarf)
return FileSpec();
// 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 FileSpec();
bool is_symlink = false;
// Always normalize our compile unit directory to get rid of redundant
// slashes and other path anomalies before we use it for path prepending
FileSpec local_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_spec, true);
if (!is_symlink)
return local_spec;
namespace fs = llvm::sys::fs;
if (fs::get_file_type(local_spec.GetPath(), false) !=
fs::file_type::symlink_file)
return local_spec;
FileSpec resolved_symlink;
const auto error = FileSystem::Readlink(local_spec, resolved_symlink);
if (error.Success())
return resolved_symlink;
return local_spec;
}
DWARFUnit *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;
DWARFUnit *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_partial_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(uint64_t(DW_INVALID_OFFSET)
<< 32), // 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_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() {
Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO);
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);
}
if (!GetGlobalPluginProperties()->IgnoreFileIndexes()) {
DWARFDataExtractor apple_names, apple_namespaces, apple_types, apple_objc;
LoadSectionData(eSectionTypeDWARFAppleNames, apple_names);
LoadSectionData(eSectionTypeDWARFAppleNamespaces, apple_namespaces);
LoadSectionData(eSectionTypeDWARFAppleTypes, apple_types);
LoadSectionData(eSectionTypeDWARFAppleObjC, apple_objc);
m_index = AppleDWARFIndex::Create(
*GetObjectFile()->GetModule(), apple_names, apple_namespaces,
apple_types, apple_objc, get_debug_str_data());
if (m_index)
return;
DWARFDataExtractor debug_names;
LoadSectionData(eSectionTypeDWARFDebugNames, debug_names);
if (debug_names.GetByteSize() > 0) {
llvm::Expected<std::unique_ptr<DebugNamesDWARFIndex>> index_or =
DebugNamesDWARFIndex::Create(*GetObjectFile()->GetModule(),
debug_names, get_debug_str_data(),
DebugInfo());
if (index_or) {
m_index = std::move(*index_or);
return;
}
LLDB_LOG_ERROR(log, index_or.takeError(),
"Unable to read .debug_names data: {0}");
}
}
m_index = llvm::make_unique<ManualDWARFIndex>(*GetObjectFile()->GetModule(),
DebugInfo());
}
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 doesnt 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_debug_types_data() {
return GetCachedSectionData(eSectionTypeDWARFDebugTypes, m_data_debug_types);
}
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);
}
const DWARFDataExtractor &SymbolFileDWARF::get_gnu_debugaltlink() {
return GetCachedSectionData(eSectionTypeDWARFGNUDebugAltLink,
m_data_gnu_debugaltlink);
}
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();
}
DWARFUnit *
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
DWARFUnit *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(DWARFUnit *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->DIE();
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,
FileSpec::Style::native);
}
LanguageType cu_language = DWARFUnit::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) {
DWARFUnit *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);
DWARFUnit *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;
DWARFUnit *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);
DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu) {
const DWARFBaseDIE cu_die = dwarf_cu->GetUnitDIEOnly();
if (cu_die) {
FileSpec 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) {
DWARFUnit *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);
DWARFUnit *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->DIE();
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;
DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu) {
const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly();
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);
DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
if (dwarf_cu == nullptr)
return false;
const DWARFBaseDIE dwarf_cu_die = dwarf_cu->GetUnitDIEOnly();
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(DWARFUnit *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();
m_index->GetObjCMethods(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(
DWARFUnit &dwarf_cu, const DWARFDebugInfoEntry &cu_die) {
// If we are using a dSYM file, we never want the standard DWO files since
// the -gmodules 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, FileSpec::Style::native);
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) {
DWARFUnit *dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly();
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,
FileSpec::Style::native);
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,
FileSpec::Style::native);
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;
DWARFUnit *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;
DWARFUnit *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());
m_index->Preload();
}
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,
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, max_matches=%u, variables)",
name.GetCString(), static_cast<const void *>(parent_decl_ctx),
max_matches);
if (!DeclContextMatchesThisSymbolFile(parent_decl_ctx))
return 0;
DWARFDebugInfo *info = DebugInfo();
if (info == NULL)
return 0;
// Remember how many variables are in the list before we search.
const uint32_t original_size = variables.GetSize();
llvm::StringRef basename;
llvm::StringRef context;
if (!CPlusPlusLanguage::ExtractContextAndIdentifier(name.GetCString(),
context, basename))
basename = name.GetStringRef();
DIEArray die_offsets;
m_index->GetGlobalVariables(ConstString(basename), 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);
// Loop invariant: Variables up to this index have been checked for context
// matches.
uint32_t pruned_idx = original_size;
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);
while (pruned_idx < variables.GetSize()) {
VariableSP var_sp = variables.GetVariableAtIndex(pruned_idx);
if (var_sp->GetName().GetStringRef().contains(name.GetStringRef()))
++pruned_idx;
else
variables.RemoveVariableAtIndex(pruned_idx);
}
if (variables.GetSize() - original_size >= max_matches)
done = true;
} break;
}
} else {
m_index->ReportInvalidDIEOffset(die_ref.die_offset,
name.GetStringRef());
}
}
}
// 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, max_matches=%u, variables) => %u",
name.GetCString(), static_cast<const void *>(parent_decl_ctx),
max_matches, num_matches);
}
return num_matches;
}
uint32_t SymbolFileDWARF::FindGlobalVariables(const RegularExpression &regex,
uint32_t max_matches,
VariableList &variables) {
Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
if (log) {
GetObjectFile()->GetModule()->LogMessage(
log,
"SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", "
"max_matches=%u, variables)",
regex.GetText().str().c_str(), max_matches);
}
DWARFDebugInfo *info = DebugInfo();
if (info == NULL)
return 0;
// Remember how many variables are in the list before we search.
const uint32_t original_size = variables.GetSize();
DIEArray die_offsets;
m_index->GetGlobalVariables(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
m_index->ReportInvalidDIEOffset(die_ref.die_offset, regex.GetText());
}
}
// Return the number of variable that were appended to the list
return variables.GetSize() - original_size;
}
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;
}
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 uint32_t original_size = sc_list.GetSize();
DWARFDebugInfo *info = DebugInfo();
if (info == NULL)
return 0;
llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies;
DIEArray offsets;
CompilerDeclContext empty_decl_ctx;
if (!parent_decl_ctx)
parent_decl_ctx = &empty_decl_ctx;
std::vector<DWARFDIE> dies;
m_index->GetFunctions(name, *info, *parent_decl_ctx, name_type_mask, dies);
for (const DWARFDIE &die: dies) {
if (resolved_dies.insert(die.GetDIE()).second)
ResolveFunction(die, 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();
DWARFDebugInfo *info = DebugInfo();
if (!info)
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.
uint32_t original_size = sc_list.GetSize();
DIEArray offsets;
m_index->GetFunctions(regex, offsets);
llvm::DenseSet<const DWARFDebugInfoEntry *> resolved_dies;
for (DIERef ref : offsets) {
DWARFDIE die = info->GetDIE(ref);
if (!die) {
m_index->ReportInvalidDIEOffset(ref.die_offset, regex.GetText());
continue;
}
if (resolved_dies.insert(die.GetDIE()).second)
ResolveFunction(die, 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++) {
DWARFUnit *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;
m_index->GetTypes(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 {
m_index->ReportInvalidDIEOffset(die_ref.die_offset,
name.GetStringRef());
}
}
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;
ConstString name = context.back().name;
if (!name)
return 0;
DIEArray die_offsets;
m_index->GetTypes(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 {
m_index->ReportInvalidDIEOffset(die_ref.die_offset,
name.GetStringRef());
}
}
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;
m_index->GetNamespaces(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 {
m_index->ReportInvalidDIEOffset(die_ref.die_offset,
name.GetStringRef());
}
}
}
}
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_partial_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(
DWARFUnit *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) {
DWARFUnit *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;
m_index->GetCompleteObjCClass(type_name, must_be_implementation, 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 {
m_index->ReportInvalidDIEOffset(die_ref.die_offset,
type_name.GetStringRef());
}
}
}
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 or DW_TAG_partial_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 or DW_TAG_partial_unit. If it isn't then
// something went wrong in the DWARFDIE::GetDeclContextDIEs()
// function.
dw_tag_t cu_tag = decl_ctx_1.GetDIEAtIndex(count1 - 1).Tag();
UNUSED_IF_ASSERT_DISABLED(cu_tag);
assert(cu_tag == DW_TAG_compile_unit || cu_tag == DW_TAG_partial_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;
m_index->GetTypes(dwarf_decl_ctx, 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 {
m_index->ReportInvalidDIEOffset(die_ref.die_offset,
type_name.GetStringRef());
}
}
}
}
}
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;
DWARFUnit *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;
DWARFUnit *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) {
DWARFUnit *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;
m_index->GetGlobalVariables(*dwarf_cu, 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
m_index->ReportInvalidDIEOffset(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.
auto debug_info_data = die.GetData();
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())) {
auto data = die.GetData();
uint32_t block_offset =
form_value.BlockData() - data.GetDataStart();
uint32_t block_length = form_value.Unsigned();
location.CopyOpcodeData(module, 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_tag == DW_TAG_partial_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 ||
parent_tag == DW_TAG_partial_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:
case DW_TAG_partial_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());
}
} 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::Dump(lldb_private::Stream &s) { m_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();
}