Skip to content

Commit da9b7d8

Browse files
labathadrian-prantl
authored andcommitted
[lldb/DWARF] Fix handling of variables with both location and const_value attributes
Class-level static constexpr variables can have both DW_AT_const_value (in the "declaration") and a DW_AT_location (in the "definition") attributes. Our code was trying to handle this, but it was brittle and hard to follow (and broken) because it was processing the attributes in the order in which they were found. Refactor the code to make the intent clearer -- DW_AT_location trumps DW_AT_const_value, and fix the bug which meant that we were not displaying these variables properly (the culprit was the delayed parsing of the const_value attribute due to a need to fetch the variable type. Differential Revision: https://reviews.llvm.org/D86615 (cherry picked from commit 9f5927e)
1 parent c377dba commit da9b7d8

File tree

3 files changed

+215
-67
lines changed

3 files changed

+215
-67
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class DWARFFormValue {
4242
DWARFFormValue(const DWARFUnit *unit) : m_unit(unit) {}
4343
DWARFFormValue(const DWARFUnit *unit, dw_form_t form)
4444
: m_unit(unit), m_form(form) {}
45+
const DWARFUnit *GetUnit() const { return m_unit; }
4546
void SetUnit(const DWARFUnit *unit) { m_unit = unit; }
4647
dw_form_t Form() const { return m_form; }
4748
dw_form_t& FormRef() { return m_form; }

lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3185,18 +3185,15 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
31853185
const char *name = nullptr;
31863186
const char *mangled = nullptr;
31873187
Declaration decl;
3188-
uint32_t i;
31893188
DWARFFormValue type_die_form;
31903189
DWARFExpression location;
31913190
bool is_external = false;
31923191
bool is_artificial = false;
3193-
bool location_is_const_value_data = false;
3194-
bool has_explicit_location = false;
3195-
DWARFFormValue const_value;
3192+
DWARFFormValue const_value_form, location_form;
31963193
Variable::RangeList scope_ranges;
31973194
// AccessType accessibility = eAccessNone;
31983195

3199-
for (i = 0; i < num_attributes; ++i) {
3196+
for (size_t i = 0; i < num_attributes; ++i) {
32003197
dw_attr_t attr = attributes.AttributeAtIndex(i);
32013198
DWARFFormValue form_value;
32023199

@@ -3226,65 +3223,11 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
32263223
is_external = form_value.Boolean();
32273224
break;
32283225
case DW_AT_const_value:
3229-
// If we have already found a DW_AT_location attribute, ignore this
3230-
// attribute.
3231-
if (!has_explicit_location) {
3232-
location_is_const_value_data = true;
3233-
// The constant value will be either a block, a data value or a
3234-
// string.
3235-
auto debug_info_data = die.GetData();
3236-
if (DWARFFormValue::IsBlockForm(form_value.Form())) {
3237-
// Retrieve the value as a block expression.
3238-
uint32_t block_offset =
3239-
form_value.BlockData() - debug_info_data.GetDataStart();
3240-
uint32_t block_length = form_value.Unsigned();
3241-
location = DWARFExpression(
3242-
module,
3243-
DataExtractor(debug_info_data, block_offset, block_length),
3244-
die.GetCU());
3245-
} else if (DWARFFormValue::IsDataForm(form_value.Form())) {
3246-
// Constant value size does not have to match the size of the
3247-
// variable. We will fetch the size of the type after we create
3248-
// it.
3249-
const_value = form_value;
3250-
} else if (const char *str = form_value.AsCString()) {
3251-
uint32_t string_length = strlen(str) + 1;
3252-
location = DWARFExpression(
3253-
module,
3254-
DataExtractor(str, string_length,
3255-
die.GetCU()->GetByteOrder(),
3256-
die.GetCU()->GetAddressByteSize()),
3257-
die.GetCU());
3258-
}
3259-
}
3226+
const_value_form = form_value;
3227+
break;
3228+
case DW_AT_location:
3229+
location_form = form_value;
32603230
break;
3261-
case DW_AT_location: {
3262-
location_is_const_value_data = false;
3263-
has_explicit_location = true;
3264-
if (DWARFFormValue::IsBlockForm(form_value.Form())) {
3265-
auto data = die.GetData();
3266-
3267-
uint32_t block_offset =
3268-
form_value.BlockData() - data.GetDataStart();
3269-
uint32_t block_length = form_value.Unsigned();
3270-
location = DWARFExpression(
3271-
module, DataExtractor(data, block_offset, block_length),
3272-
die.GetCU());
3273-
} else {
3274-
DataExtractor data = die.GetCU()->GetLocationData();
3275-
dw_offset_t offset = form_value.Unsigned();
3276-
if (form_value.Form() == DW_FORM_loclistx)
3277-
offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1);
3278-
if (data.ValidOffset(offset)) {
3279-
data = DataExtractor(data, offset, data.GetByteSize() - offset);
3280-
location = DWARFExpression(module, data, die.GetCU());
3281-
assert(func_low_pc != LLDB_INVALID_ADDRESS);
3282-
location.SetLocationListAddresses(
3283-
attributes.CompileUnitAtIndex(i)->GetBaseAddress(),
3284-
func_low_pc);
3285-
}
3286-
}
3287-
} break;
32883231
case DW_AT_specification:
32893232
spec_die = form_value.Reference();
32903233
break;
@@ -3314,6 +3257,66 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
33143257
IsSwiftLanguage(sc.comp_unit->GetLanguage()))
33153258
mangled = NULL;
33163259

3260+
// Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g.
3261+
// for static constexpr member variables -- DW_AT_const_value will be
3262+
// present in the class declaration and DW_AT_location in the DIE defining
3263+
// the member.
3264+
bool location_is_const_value_data = false;
3265+
bool has_explicit_location = false;
3266+
bool use_type_size_for_value = false;
3267+
if (location_form.IsValid()) {
3268+
has_explicit_location = true;
3269+
if (DWARFFormValue::IsBlockForm(location_form.Form())) {
3270+
const DWARFDataExtractor &data = die.GetData();
3271+
3272+
uint32_t block_offset =
3273+
location_form.BlockData() - data.GetDataStart();
3274+
uint32_t block_length = location_form.Unsigned();
3275+
location = DWARFExpression(
3276+
module, DataExtractor(data, block_offset, block_length),
3277+
die.GetCU());
3278+
} else {
3279+
DataExtractor data = die.GetCU()->GetLocationData();
3280+
dw_offset_t offset = location_form.Unsigned();
3281+
if (location_form.Form() == DW_FORM_loclistx)
3282+
offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1);
3283+
if (data.ValidOffset(offset)) {
3284+
data = DataExtractor(data, offset, data.GetByteSize() - offset);
3285+
location = DWARFExpression(module, data, die.GetCU());
3286+
assert(func_low_pc != LLDB_INVALID_ADDRESS);
3287+
location.SetLocationListAddresses(
3288+
location_form.GetUnit()->GetBaseAddress(), func_low_pc);
3289+
}
3290+
}
3291+
} else if (const_value_form.IsValid()) {
3292+
location_is_const_value_data = true;
3293+
// The constant value will be either a block, a data value or a
3294+
// string.
3295+
const DWARFDataExtractor &debug_info_data = die.GetData();
3296+
if (DWARFFormValue::IsBlockForm(const_value_form.Form())) {
3297+
// Retrieve the value as a block expression.
3298+
uint32_t block_offset =
3299+
const_value_form.BlockData() - debug_info_data.GetDataStart();
3300+
uint32_t block_length = const_value_form.Unsigned();
3301+
location = DWARFExpression(
3302+
module,
3303+
DataExtractor(debug_info_data, block_offset, block_length),
3304+
die.GetCU());
3305+
} else if (DWARFFormValue::IsDataForm(const_value_form.Form())) {
3306+
// Constant value size does not have to match the size of the
3307+
// variable. We will fetch the size of the type after we create
3308+
// it.
3309+
use_type_size_for_value = true;
3310+
} else if (const char *str = const_value_form.AsCString()) {
3311+
uint32_t string_length = strlen(str) + 1;
3312+
location = DWARFExpression(
3313+
module,
3314+
DataExtractor(str, string_length, die.GetCU()->GetByteOrder(),
3315+
die.GetCU()->GetAddressByteSize()),
3316+
die.GetCU());
3317+
}
3318+
}
3319+
33173320
const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die);
33183321
const dw_tag_t parent_tag = die.GetParent().Tag();
33193322
bool is_static_member =
@@ -3493,12 +3496,12 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
34933496
}
34943497

34953498
if (symbol_context_scope) {
3496-
SymbolFileTypeSP type_sp(
3497-
new SymbolFileType(*this, GetUID(type_die_form.Reference())));
3499+
auto type_sp = std::make_shared<SymbolFileType>(
3500+
*this, GetUID(type_die_form.Reference()));
34983501

3499-
if (const_value.Form() && type_sp && type_sp->GetType())
3502+
if (use_type_size_for_value && type_sp->GetType())
35003503
location.UpdateValue(
3501-
const_value.Unsigned(),
3504+
const_value_form.Unsigned(),
35023505
type_sp->GetType()->GetByteSize(nullptr).getValueOr(0),
35033506
die.GetCU()->GetAddressByteSize());
35043507

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
## Test that we don't get confused by variables with both location and
2+
## const_value attributes. Such values are produced in C++ for class-level
3+
## static constexpr variables.
4+
5+
# REQUIRES: x86
6+
7+
# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux %s -o %t
8+
# RUN: %lldb %t -o "target variable A::x A::y" -o exit | FileCheck %s
9+
10+
# CHECK-LABEL: target variable
11+
# CHECK: (const int) A::x = 142
12+
# CHECK: (const int) A::y = 242
13+
14+
.section .rodata,"a",@progbits
15+
.p2align 2
16+
_ZN1A1xE:
17+
.long 142
18+
_ZN1A1yE:
19+
.long 242
20+
21+
.section .debug_abbrev,"",@progbits
22+
.byte 1 # Abbreviation Code
23+
.byte 17 # DW_TAG_compile_unit
24+
.byte 1 # DW_CHILDREN_yes
25+
.byte 37 # DW_AT_producer
26+
.byte 8 # DW_FORM_string
27+
.byte 3 # DW_AT_name
28+
.byte 8 # DW_FORM_string
29+
.byte 0 # EOM(1)
30+
.byte 0 # EOM(2)
31+
.byte 3 # Abbreviation Code
32+
.byte 19 # DW_TAG_structure_type
33+
.byte 1 # DW_CHILDREN_yes
34+
.byte 3 # DW_AT_name
35+
.byte 8 # DW_FORM_string
36+
.byte 11 # DW_AT_byte_size
37+
.byte 11 # DW_FORM_data1
38+
.byte 0 # EOM(1)
39+
.byte 0 # EOM(2)
40+
.byte 4 # Abbreviation Code
41+
.byte 13 # DW_TAG_member
42+
.byte 0 # DW_CHILDREN_no
43+
.byte 3 # DW_AT_name
44+
.byte 8 # DW_FORM_string
45+
.byte 73 # DW_AT_type
46+
.byte 19 # DW_FORM_ref4
47+
.byte 60 # DW_AT_declaration
48+
.byte 25 # DW_FORM_flag_present
49+
.byte 28 # DW_AT_const_value
50+
.byte 13 # DW_FORM_sdata
51+
.byte 0 # EOM(1)
52+
.byte 0 # EOM(2)
53+
.byte 5 # Abbreviation Code
54+
.byte 38 # DW_TAG_const_type
55+
.byte 0 # DW_CHILDREN_no
56+
.byte 73 # DW_AT_type
57+
.byte 19 # DW_FORM_ref4
58+
.byte 0 # EOM(1)
59+
.byte 0 # EOM(2)
60+
.byte 6 # Abbreviation Code
61+
.byte 36 # DW_TAG_base_type
62+
.byte 0 # DW_CHILDREN_no
63+
.byte 3 # DW_AT_name
64+
.byte 8 # DW_FORM_string
65+
.byte 62 # DW_AT_encoding
66+
.byte 11 # DW_FORM_data1
67+
.byte 11 # DW_AT_byte_size
68+
.byte 11 # DW_FORM_data1
69+
.byte 0 # EOM(1)
70+
.byte 0 # EOM(2)
71+
.byte 7 # Abbreviation Code
72+
.byte 52 # DW_TAG_variable
73+
.byte 0 # DW_CHILDREN_no
74+
.byte 71 # DW_AT_specification
75+
.byte 19 # DW_FORM_ref4
76+
.byte 2 # DW_AT_location
77+
.byte 24 # DW_FORM_exprloc
78+
.byte 110 # DW_AT_linkage_name
79+
.byte 8 # DW_FORM_string
80+
.byte 0 # EOM(1)
81+
.byte 0 # EOM(2)
82+
## This deliberately inverts the order of the specification and location
83+
## attributes.
84+
.byte 8 # Abbreviation Code
85+
.byte 52 # DW_TAG_variable
86+
.byte 0 # DW_CHILDREN_no
87+
.byte 2 # DW_AT_location
88+
.byte 24 # DW_FORM_exprloc
89+
.byte 71 # DW_AT_specification
90+
.byte 19 # DW_FORM_ref4
91+
.byte 110 # DW_AT_linkage_name
92+
.byte 8 # DW_FORM_string
93+
.byte 0 # EOM(1)
94+
.byte 0 # EOM(2)
95+
.byte 0 # EOM(3)
96+
97+
.section .debug_info,"",@progbits
98+
.Lcu_begin0:
99+
.long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit
100+
.Ldebug_info_start0:
101+
.short 4 # DWARF version number
102+
.long .debug_abbrev # Offset Into Abbrev. Section
103+
.byte 8 # Address Size (in bytes)
104+
.byte 1 # Abbrev DW_TAG_compile_unit
105+
.asciz "Hand-written DWARF" # DW_AT_producer
106+
.asciz "a.cc" # DW_AT_name
107+
.byte 7 # Abbrev DW_TAG_variable
108+
.long .LA__x-.Lcu_begin0 # DW_AT_specification
109+
.byte 9 # DW_AT_location
110+
.byte 3
111+
.quad _ZN1A1xE
112+
.asciz "_ZN1A1xE" # DW_AT_linkage_name
113+
.byte 8 # Abbrev DW_TAG_variable
114+
.byte 9 # DW_AT_location
115+
.byte 3
116+
.quad _ZN1A1yE
117+
.long .LA__y-.Lcu_begin0 # DW_AT_specification
118+
.asciz "_ZN1A1yE" # DW_AT_linkage_name
119+
.byte 3 # Abbrev DW_TAG_structure_type
120+
.asciz "A" # DW_AT_name
121+
.byte 1 # DW_AT_byte_size
122+
.LA__x:
123+
.byte 4 # Abbrev DW_TAG_member
124+
.asciz "x" # DW_AT_name
125+
.long .Lconst_int-.Lcu_begin0 # DW_AT_type
126+
# DW_AT_declaration
127+
.sleb128 147 # DW_AT_const_value
128+
.LA__y:
129+
.byte 4 # Abbrev DW_TAG_member
130+
.asciz "y" # DW_AT_name
131+
.long .Lconst_int-.Lcu_begin0 # DW_AT_type
132+
# DW_AT_declaration
133+
.sleb128 247 # DW_AT_const_value
134+
.byte 0 # End Of Children Mark
135+
.Lconst_int:
136+
.byte 5 # Abbrev DW_TAG_const_type
137+
.long .Lint-.Lcu_begin0 # DW_AT_type
138+
.Lint:
139+
.byte 6 # Abbrev DW_TAG_base_type
140+
.asciz "int" # DW_AT_name
141+
.byte 5 # DW_AT_encoding
142+
.byte 4 # DW_AT_byte_size
143+
.byte 0 # End Of Children Mark
144+
.Ldebug_info_end0:

0 commit comments

Comments
 (0)