Skip to content

Commit bac4247

Browse files
Merge pull request #1949 from adrian-prantl/D86615
[lldb/DWARF] Fix handling of variables with both location and const_v…
2 parents e3ec22d + a107763 commit bac4247

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
@@ -3111,18 +3111,15 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
31113111
const char *name = nullptr;
31123112
const char *mangled = nullptr;
31133113
Declaration decl;
3114-
uint32_t i;
31153114
DWARFFormValue type_die_form;
31163115
DWARFExpression location;
31173116
bool is_external = false;
31183117
bool is_artificial = false;
3119-
bool location_is_const_value_data = false;
3120-
bool has_explicit_location = false;
3121-
DWARFFormValue const_value;
3118+
DWARFFormValue const_value_form, location_form;
31223119
Variable::RangeList scope_ranges;
31233120
// AccessType accessibility = eAccessNone;
31243121

3125-
for (i = 0; i < num_attributes; ++i) {
3122+
for (size_t i = 0; i < num_attributes; ++i) {
31263123
dw_attr_t attr = attributes.AttributeAtIndex(i);
31273124
DWARFFormValue form_value;
31283125

@@ -3152,65 +3149,11 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
31523149
is_external = form_value.Boolean();
31533150
break;
31543151
case DW_AT_const_value:
3155-
// If we have already found a DW_AT_location attribute, ignore this
3156-
// attribute.
3157-
if (!has_explicit_location) {
3158-
location_is_const_value_data = true;
3159-
// The constant value will be either a block, a data value or a
3160-
// string.
3161-
auto debug_info_data = die.GetData();
3162-
if (DWARFFormValue::IsBlockForm(form_value.Form())) {
3163-
// Retrieve the value as a block expression.
3164-
uint32_t block_offset =
3165-
form_value.BlockData() - debug_info_data.GetDataStart();
3166-
uint32_t block_length = form_value.Unsigned();
3167-
location = DWARFExpression(
3168-
module,
3169-
DataExtractor(debug_info_data, block_offset, block_length),
3170-
die.GetCU());
3171-
} else if (DWARFFormValue::IsDataForm(form_value.Form())) {
3172-
// Constant value size does not have to match the size of the
3173-
// variable. We will fetch the size of the type after we create
3174-
// it.
3175-
const_value = form_value;
3176-
} else if (const char *str = form_value.AsCString()) {
3177-
uint32_t string_length = strlen(str) + 1;
3178-
location = DWARFExpression(
3179-
module,
3180-
DataExtractor(str, string_length,
3181-
die.GetCU()->GetByteOrder(),
3182-
die.GetCU()->GetAddressByteSize()),
3183-
die.GetCU());
3184-
}
3185-
}
3152+
const_value_form = form_value;
3153+
break;
3154+
case DW_AT_location:
3155+
location_form = form_value;
31863156
break;
3187-
case DW_AT_location: {
3188-
location_is_const_value_data = false;
3189-
has_explicit_location = true;
3190-
if (DWARFFormValue::IsBlockForm(form_value.Form())) {
3191-
auto data = die.GetData();
3192-
3193-
uint32_t block_offset =
3194-
form_value.BlockData() - data.GetDataStart();
3195-
uint32_t block_length = form_value.Unsigned();
3196-
location = DWARFExpression(
3197-
module, DataExtractor(data, block_offset, block_length),
3198-
die.GetCU());
3199-
} else {
3200-
DataExtractor data = die.GetCU()->GetLocationData();
3201-
dw_offset_t offset = form_value.Unsigned();
3202-
if (form_value.Form() == DW_FORM_loclistx)
3203-
offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1);
3204-
if (data.ValidOffset(offset)) {
3205-
data = DataExtractor(data, offset, data.GetByteSize() - offset);
3206-
location = DWARFExpression(module, data, die.GetCU());
3207-
assert(func_low_pc != LLDB_INVALID_ADDRESS);
3208-
location.SetLocationListAddresses(
3209-
attributes.CompileUnitAtIndex(i)->GetBaseAddress(),
3210-
func_low_pc);
3211-
}
3212-
}
3213-
} break;
32143157
case DW_AT_specification:
32153158
spec_die = form_value.Reference();
32163159
break;
@@ -3236,6 +3179,66 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
32363179
}
32373180
}
32383181

3182+
// Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g.
3183+
// for static constexpr member variables -- DW_AT_const_value will be
3184+
// present in the class declaration and DW_AT_location in the DIE defining
3185+
// the member.
3186+
bool location_is_const_value_data = false;
3187+
bool has_explicit_location = false;
3188+
bool use_type_size_for_value = false;
3189+
if (location_form.IsValid()) {
3190+
has_explicit_location = true;
3191+
if (DWARFFormValue::IsBlockForm(location_form.Form())) {
3192+
const DWARFDataExtractor &data = die.GetData();
3193+
3194+
uint32_t block_offset =
3195+
location_form.BlockData() - data.GetDataStart();
3196+
uint32_t block_length = location_form.Unsigned();
3197+
location = DWARFExpression(
3198+
module, DataExtractor(data, block_offset, block_length),
3199+
die.GetCU());
3200+
} else {
3201+
DataExtractor data = die.GetCU()->GetLocationData();
3202+
dw_offset_t offset = location_form.Unsigned();
3203+
if (location_form.Form() == DW_FORM_loclistx)
3204+
offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1);
3205+
if (data.ValidOffset(offset)) {
3206+
data = DataExtractor(data, offset, data.GetByteSize() - offset);
3207+
location = DWARFExpression(module, data, die.GetCU());
3208+
assert(func_low_pc != LLDB_INVALID_ADDRESS);
3209+
location.SetLocationListAddresses(
3210+
location_form.GetUnit()->GetBaseAddress(), func_low_pc);
3211+
}
3212+
}
3213+
} else if (const_value_form.IsValid()) {
3214+
location_is_const_value_data = true;
3215+
// The constant value will be either a block, a data value or a
3216+
// string.
3217+
const DWARFDataExtractor &debug_info_data = die.GetData();
3218+
if (DWARFFormValue::IsBlockForm(const_value_form.Form())) {
3219+
// Retrieve the value as a block expression.
3220+
uint32_t block_offset =
3221+
const_value_form.BlockData() - debug_info_data.GetDataStart();
3222+
uint32_t block_length = const_value_form.Unsigned();
3223+
location = DWARFExpression(
3224+
module,
3225+
DataExtractor(debug_info_data, block_offset, block_length),
3226+
die.GetCU());
3227+
} else if (DWARFFormValue::IsDataForm(const_value_form.Form())) {
3228+
// Constant value size does not have to match the size of the
3229+
// variable. We will fetch the size of the type after we create
3230+
// it.
3231+
use_type_size_for_value = true;
3232+
} else if (const char *str = const_value_form.AsCString()) {
3233+
uint32_t string_length = strlen(str) + 1;
3234+
location = DWARFExpression(
3235+
module,
3236+
DataExtractor(str, string_length, die.GetCU()->GetByteOrder(),
3237+
die.GetCU()->GetAddressByteSize()),
3238+
die.GetCU());
3239+
}
3240+
}
3241+
32393242
const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die);
32403243
const dw_tag_t parent_tag = die.GetParent().Tag();
32413244
bool is_static_member =
@@ -3415,12 +3418,12 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
34153418
}
34163419

34173420
if (symbol_context_scope) {
3418-
SymbolFileTypeSP type_sp(
3419-
new SymbolFileType(*this, GetUID(type_die_form.Reference())));
3421+
auto type_sp = std::make_shared<SymbolFileType>(
3422+
*this, GetUID(type_die_form.Reference()));
34203423

3421-
if (const_value.Form() && type_sp && type_sp->GetType())
3424+
if (use_type_size_for_value && type_sp->GetType())
34223425
location.UpdateValue(
3423-
const_value.Unsigned(),
3426+
const_value_form.Unsigned(),
34243427
type_sp->GetType()->GetByteSize(nullptr).getValueOr(0),
34253428
die.GetCU()->GetAddressByteSize());
34263429

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)