[lldb] Reduce intentation in SymbolFileDWARF::ParseVariableDIE

using early exits. NFC.
This commit is contained in:
Pavel Labath 2020-08-27 15:30:12 +02:00
parent 9300ca5411
commit 1f9595ede4
1 changed files with 315 additions and 328 deletions

View File

@ -3091,363 +3091,350 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
if (die.GetDWARF() != this)
return die.GetDWARF()->ParseVariableDIE(sc, die, func_low_pc);
VariableSP var_sp;
if (!die)
return var_sp;
return nullptr;
var_sp = GetDIEToVariable()[die.GetDIE()];
if (var_sp)
if (VariableSP var_sp = GetDIEToVariable()[die.GetDIE()])
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 = nullptr;
const char *mangled = nullptr;
Declaration decl;
DWARFFormValue type_die_form;
DWARFExpression location;
bool is_external = false;
bool is_artificial = false;
DWARFFormValue const_value_form, location_form;
Variable::RangeList scope_ranges;
// AccessType accessibility = eAccessNone;
if (tag != DW_TAG_variable && tag != DW_TAG_constant &&
(tag != DW_TAG_formal_parameter || !sc.function))
return nullptr;
for (size_t i = 0; i < num_attributes; ++i) {
dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
DWARFAttributes attributes;
const size_t num_attributes = die.GetAttributes(attributes);
DWARFDIE spec_die;
VariableSP var_sp;
const char *name = nullptr;
const char *mangled = nullptr;
Declaration decl;
DWARFFormValue type_die_form;
DWARFExpression location;
bool is_external = false;
bool is_artificial = false;
DWARFFormValue const_value_form, location_form;
Variable::RangeList scope_ranges;
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:
const_value_form = form_value;
break;
case DW_AT_location:
location_form = form_value;
break;
case DW_AT_specification:
spec_die = form_value.Reference();
break;
case DW_AT_start_scope:
// TODO: Implement this.
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;
}
}
for (size_t i = 0; i < num_attributes; ++i) {
dw_attr_t attr = attributes.AttributeAtIndex(i);
DWARFFormValue form_value;
if (!attributes.ExtractFormValueAtIndex(i, form_value))
continue;
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:
const_value_form = form_value;
break;
case DW_AT_location:
location_form = form_value;
break;
case DW_AT_specification:
spec_die = form_value.Reference();
break;
case DW_AT_start_scope:
// TODO: Implement this.
break;
case DW_AT_artificial:
is_artificial = form_value.Boolean();
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;
}
}
// Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g.
// for static constexpr member variables -- DW_AT_const_value will be
// present in the class declaration and DW_AT_location in the DIE defining
// the member.
bool location_is_const_value_data = false;
bool has_explicit_location = false;
bool use_type_size_for_value = false;
if (location_form.IsValid()) {
has_explicit_location = true;
if (DWARFFormValue::IsBlockForm(location_form.Form())) {
const DWARFDataExtractor &data = die.GetData();
uint32_t block_offset = location_form.BlockData() - data.GetDataStart();
uint32_t block_length = location_form.Unsigned();
location = DWARFExpression(
module, DataExtractor(data, block_offset, block_length), die.GetCU());
} else {
DataExtractor data = die.GetCU()->GetLocationData();
dw_offset_t offset = location_form.Unsigned();
if (location_form.Form() == DW_FORM_loclistx)
offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1);
if (data.ValidOffset(offset)) {
data = DataExtractor(data, offset, data.GetByteSize() - offset);
location = DWARFExpression(module, data, die.GetCU());
assert(func_low_pc != LLDB_INVALID_ADDRESS);
location.SetLocationListAddresses(
location_form.GetUnit()->GetBaseAddress(), func_low_pc);
}
}
} else if (const_value_form.IsValid()) {
location_is_const_value_data = true;
// The constant value will be either a block, a data value or a
// string.
const DWARFDataExtractor &debug_info_data = die.GetData();
if (DWARFFormValue::IsBlockForm(const_value_form.Form())) {
// Retrieve the value as a block expression.
uint32_t block_offset =
const_value_form.BlockData() - debug_info_data.GetDataStart();
uint32_t block_length = const_value_form.Unsigned();
location = DWARFExpression(
module, DataExtractor(debug_info_data, block_offset, block_length),
die.GetCU());
} else if (DWARFFormValue::IsDataForm(const_value_form.Form())) {
// Constant value size does not have to match the size of the
// variable. We will fetch the size of the type after we create
// it.
use_type_size_for_value = true;
} else if (const char *str = const_value_form.AsCString()) {
uint32_t string_length = strlen(str) + 1;
location = DWARFExpression(
module,
DataExtractor(str, string_length, die.GetCU()->GetByteOrder(),
die.GetCU()->GetAddressByteSize()),
die.GetCU());
}
}
// Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g.
// for static constexpr member variables -- DW_AT_const_value will be
// present in the class declaration and DW_AT_location in the DIE defining
// the member.
bool location_is_const_value_data = false;
bool has_explicit_location = false;
bool use_type_size_for_value = false;
if (location_form.IsValid()) {
has_explicit_location = true;
if (DWARFFormValue::IsBlockForm(location_form.Form())) {
const DWARFDataExtractor &data = die.GetData();
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);
uint32_t block_offset =
location_form.BlockData() - data.GetDataStart();
uint32_t block_length = location_form.Unsigned();
location = DWARFExpression(
module, DataExtractor(data, block_offset, block_length),
die.GetCU());
} else {
DataExtractor data = die.GetCU()->GetLocationData();
dw_offset_t offset = location_form.Unsigned();
if (location_form.Form() == DW_FORM_loclistx)
offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1);
if (data.ValidOffset(offset)) {
data = DataExtractor(data, offset, data.GetByteSize() - offset);
location = DWARFExpression(module, data, die.GetCU());
assert(func_low_pc != LLDB_INVALID_ADDRESS);
location.SetLocationListAddresses(
location_form.GetUnit()->GetBaseAddress(), func_low_pc);
}
}
} else if (const_value_form.IsValid()) {
location_is_const_value_data = true;
// The constant value will be either a block, a data value or a
// string.
const DWARFDataExtractor &debug_info_data = die.GetData();
if (DWARFFormValue::IsBlockForm(const_value_form.Form())) {
// Retrieve the value as a block expression.
uint32_t block_offset =
const_value_form.BlockData() - debug_info_data.GetDataStart();
uint32_t block_length = const_value_form.Unsigned();
location = DWARFExpression(
module,
DataExtractor(debug_info_data, block_offset, block_length),
die.GetCU());
} else if (DWARFFormValue::IsDataForm(const_value_form.Form())) {
// Constant value size does not have to match the size of the
// variable. We will fetch the size of the type after we create
// it.
use_type_size_for_value = true;
} else if (const char *str = const_value_form.AsCString()) {
uint32_t string_length = strlen(str) + 1;
location = DWARFExpression(
module,
DataExtractor(str, string_length, die.GetCU()->GetByteOrder(),
die.GetCU()->GetAddressByteSize()),
die.GetCU());
}
ValueType scope = eValueTypeInvalid;
const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
SymbolContextScope *symbol_context_scope = nullptr;
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(GetLanguage(*die.GetCU())))
mangled =
GetDWARFDeclContext(die).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,
nullptr);
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 (debug_map_symfile)
// Set the module of the expression to the linked module
// instead of the oject file so the relocated address can be
// found there.
location.SetModule(debug_map_symfile->GetObjectFile()->GetModule());
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);
if (is_static_lifetime) {
if (is_external)
scope = eValueTypeVariableGlobal;
else
scope = eValueTypeVariableStatic;
ValueType scope = eValueTypeInvalid;
const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die);
SymbolContextScope *symbol_context_scope = nullptr;
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(GetLanguage(*die.GetCU())))
mangled = GetDWARFDeclContext(die)
.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,
nullptr);
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 (debug_map_symfile)
// Set the module of the expression to the linked module
// instead of the oject file so the relocated address can be
// found there.
location.SetModule(debug_map_symfile->GetObjectFile()->GetModule());
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 (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 &&
die.GetDIE()->IsGlobalOrStaticScopeVariable())
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 (!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;
}
}
}
if (symbol_context_scope == nullptr) {
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 == nullptr)
symbol_context_scope = sc.function;
} else {
if (location_is_const_value_data &&
die.GetDIE()->IsGlobalOrStaticScopeVariable())
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;
}
break;
default:
symbol_context_scope = sc.comp_unit;
break;
}
}
if (symbol_context_scope) {
auto type_sp = std::make_shared<SymbolFileType>(
*this, GetUID(type_die_form.Reference()));
if (use_type_size_for_value && type_sp->GetType())
location.UpdateValue(
const_value_form.Unsigned(),
type_sp->GetType()->GetByteSize(nullptr).getValueOr(0),
die.GetCU()->GetAddressByteSize());
var_sp = std::make_shared<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;
}
if (symbol_context_scope == nullptr) {
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 == nullptr)
symbol_context_scope = sc.function;
}
break;
default:
symbol_context_scope = sc.comp_unit;
break;
}
}
if (symbol_context_scope) {
auto type_sp = std::make_shared<SymbolFileType>(
*this, GetUID(type_die_form.Reference()));
if (use_type_size_for_value && type_sp->GetType())
location.UpdateValue(
const_value_form.Unsigned(),
type_sp->GetType()->GetByteSize(nullptr).getValueOr(0),
die.GetCU()->GetAddressByteSize());
var_sp = std::make_shared<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;
}