Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3142,7 +3142,11 @@ void DWARFASTParserClang::ParseSingleMember(
uint64_t parent_byte_size =
parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);

if (attrs.member_byte_offset >= parent_byte_size) {
// If the attrs.member_byte_offset is still set to UINT32_MAX this means
// that the DW_TAG_member didn't have a DW_AT_data_member_location, so
// don't emit an error if this is the case.
if (attrs.member_byte_offset != UINT32_MAX &&
Copy link
Member

@Michael137 Michael137 Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Though there's a couple of follow-ups i think we could do:

  1. Would be nice if member_byte_offset was an optional
  2. Why is Clang emitting DW_AT_data_member_location for union members? Aren't they always 0x0 anyway. I assume that's why GCC chooses to omit them. Would be nice for Clang and GCC to align on this.
  3. The history of this codeblock is quite interesting. It seems to work around a Clang debug-info generation bug from before 2012 (around Clang-4). Looks like what we're trying to do here is to fixup the array type from arr[1] to arr[0]. I'm not even sure if this still works (there are no tests, prior to the one you added).

attrs.member_byte_offset >= parent_byte_size) {
if (member_array_size != 1 &&
(member_array_size != 0 ||
attrs.member_byte_offset > parent_byte_size)) {
Expand Down
182 changes: 182 additions & 0 deletions lldb/test/Shell/SymbolFile/DWARF/union-types-no-member-location.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# This test produces DWARF that contains a union type whose DW_TAG_member does
# not have a DW_AT_data_member_location set to zero. This is how GCC emits
# debug information for unions. There was code in the DWARFASTParserClang that
# was emitting an invalid error in this case. This test verifies that this
# error does not get emitted.
#
# 0x0000000b: DW_TAG_compile_unit
# DW_AT_name ("main.cpp")
# DW_AT_language (DW_LANG_C)
#
# 0x00000011: DW_TAG_base_type
# DW_AT_name ("int")
# DW_AT_encoding (DW_ATE_signed_char)
# DW_AT_byte_size (0x04)
#
# 0x00000018: DW_TAG_base_type
# DW_AT_name ("__ARRAY_SIZE_TYPE__")
# DW_AT_encoding (DW_ATE_unsigned)
# DW_AT_byte_size (0x08)
#
# 0x0000001f: DW_TAG_array_type
# DW_AT_type (0x00000011 "int")
#
# 0x00000024: DW_TAG_subrange_type
# DW_AT_type (0x00000018 "__ARRAY_SIZE_TYPE__")
# DW_AT_count (0x20)
#
# 0x0000002a: NULL
#
# 0x0000002b: DW_TAG_union_type
# DW_AT_name ("UnionType")
# DW_AT_byte_size (0x20)
#
# 0x00000031: DW_TAG_member
# DW_AT_name ("array")
# DW_AT_type (0x0000001f "int[32]")
#
# 0x0000003a: NULL
#
# 0x0000003b: DW_TAG_subprogram
# DW_AT_low_pc (0x0000000000001000)
# DW_AT_high_pc (0x0000000000001050)
# DW_AT_name ("foo")
# DW_AT_type (0x00000031 "array")
#
# 0x00000054: NULL

# RUN: yaml2obj %s > %t
# RUN: lldb-test symbols --name=UnionType --find=type %t > %t.stdout
# RUN: cat %t.stdout | FileCheck --check-prefix=STDOUT %s
# RUN: lldb-test symbols --name=UnionType --find=type %t 2> %t.stderr
# RUN: cat %t.stderr | FileCheck --allow-empty --check-prefix=STDERR %s

# STDOUT: Found 1 types:
# STDOUT: 0x{{[0-9a-fA-F]+}}: Type{0x0000002b} , name = "UnionType", size = 32, compiler_type = 0x{{[0-9a-fA-F]+}} union UnionType {

# STDERR-NOT: error: union-types-no-member-location.yaml.tmp 0x00000031: DW_TAG_member 'array' refers to type 0x000000000000001f which extends beyond the bounds of 0x0000002b

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
DWARF:
debug_str:
- ''
- main.cpp
- int
- __ARRAY_SIZE_TYPE__
- UnionType
- array
debug_abbrev:
- ID: 0
Table:
- Code: 0x1
Tag: DW_TAG_compile_unit
Children: DW_CHILDREN_yes
Attributes:
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Attribute: DW_AT_language
Form: DW_FORM_udata
- Code: 0x2
Tag: DW_TAG_base_type
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Attribute: DW_AT_encoding
Form: DW_FORM_data1
- Attribute: DW_AT_byte_size
Form: DW_FORM_data1
- Code: 0x3
Tag: DW_TAG_array_type
Children: DW_CHILDREN_yes
Attributes:
- Attribute: DW_AT_type
Form: DW_FORM_ref4
- Code: 0x4
Tag: DW_TAG_subrange_type
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_type
Form: DW_FORM_ref4
- Attribute: DW_AT_count
Form: DW_FORM_data1
- Code: 0x5
Tag: DW_TAG_union_type
Children: DW_CHILDREN_yes
Attributes:
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Attribute: DW_AT_byte_size
Form: DW_FORM_data1
- Code: 0x6
Tag: DW_TAG_member
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_name
Form: DW_FORM_strp
- Attribute: DW_AT_type
Form: DW_FORM_ref4
- Code: 0x7
Tag: DW_TAG_subprogram
Children: DW_CHILDREN_no
Attributes:
- Attribute: DW_AT_low_pc
Form: DW_FORM_addr
- Attribute: DW_AT_high_pc
Form: DW_FORM_addr
- Attribute: DW_AT_name
Form: DW_FORM_string
- Attribute: DW_AT_type
Form: DW_FORM_ref4
debug_info:
- Length: 0x51
Version: 4
AbbrevTableID: 0
AbbrOffset: 0x0
AddrSize: 8
Entries:
- AbbrCode: 0x1
Values:
- Value: 0x1
- Value: 0x2
- AbbrCode: 0x2
Values:
- Value: 0xA
- Value: 0x6
- Value: 0x4
- AbbrCode: 0x2
Values:
- Value: 0xE
- Value: 0x7
- Value: 0x8
- AbbrCode: 0x3
Values:
- Value: 0x11
- AbbrCode: 0x4
Values:
- Value: 0x18
- Value: 0x20
- AbbrCode: 0x0
- AbbrCode: 0x5
Values:
- Value: 0x22
- Value: 0x20
- AbbrCode: 0x6
Values:
- Value: 0x2C
- Value: 0x1F
- AbbrCode: 0x0
- AbbrCode: 0x7
Values:
- Value: 0x1000
- Value: 0x1050
- Value: 0xDEADBEEFDEADBEEF
CStr: foo
- Value: 0x31
- AbbrCode: 0x0
...
Loading