Skip to content

Commit 119aecb

Browse files
authored
[DebugInfo] Emit negative DW_AT_bit_offset in explicit signed form (#87994)
Before this patch, the value of DW_AT_bit_offset, used for bitfields before DWARF version 4, was always emitted as an unsigned integer using the form DW_FORM_data<n>. If the value was originally a signed integer, for instance in the case of negative offsets, it was up to debug information consumers to re-cast it to a signed integer. This is problematic since the burden of deciding if the value should be read as signed or unsigned was put onto the debug info consumers: the DWARF specification doesn't define DW_AT_bit_offset's underlying type. If a debugger decided to interpret this attribute in the form data<n> as unsigned, then negative offsets would be completely broken. The DWARF specification version 3 mentions in the Data Representation section, page 127: > If one of the DW_FORM_data<n> forms is used to represent a signed or unsigned integer, it can be hard for a consumer to discover the context necessary to determine which interpretation is intended. Producers are therefore strongly encouraged to use DW_FORM_sdata or DW_FORM_udata for signed and unsigned integers respectively, rather than DW_FORM_data<n>. Therefore, the proposal is to use DW_FORM_sdata, which is explicitly signed. This is an indication to consumers that the offset must be parsed unambiguously as a signed integer. Finally, gcc already uses DW_FORM_sdata for negative offsets, fixing the potential ambiguity altogether. This patch mimics gcc's behaviour by emitting negative values of DW_AT_bit_offset using the DW_FORM_sdata form. This eliminates any potential misinterpretation. One could argue that all values should use DW_FORM_sdata, but for the sake of parity with gcc, it is safe to restrict the change to negative values.
1 parent 61d4ca8 commit 119aecb

File tree

4 files changed

+12
-5
lines changed

4 files changed

+12
-5
lines changed

llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "llvm/Target/TargetLoweringObjectFile.h"
3131
#include <cassert>
3232
#include <cstdint>
33+
#include <limits>
3334
#include <string>
3435
#include <utility>
3536

@@ -1649,7 +1650,8 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
16491650
addUInt(MemberDie, dwarf::DW_AT_byte_size, std::nullopt, FieldSize / 8);
16501651
addUInt(MemberDie, dwarf::DW_AT_bit_size, std::nullopt, Size);
16511652

1652-
uint64_t Offset = DT->getOffsetInBits();
1653+
assert(DT->getOffsetInBits() <= std::numeric_limits<int64_t>::max());
1654+
int64_t Offset = DT->getOffsetInBits();
16531655
// We can't use DT->getAlignInBits() here: AlignInBits for member type
16541656
// is non-zero if and only if alignment was forced (e.g. _Alignas()),
16551657
// which can't be done with bitfields. Thus we use FieldSize here.
@@ -1669,7 +1671,12 @@ DIE &DwarfUnit::constructMemberDIE(DIE &Buffer, const DIDerivedType *DT) {
16691671
if (Asm->getDataLayout().isLittleEndian())
16701672
Offset = FieldSize - (Offset + Size);
16711673

1672-
addUInt(MemberDie, dwarf::DW_AT_bit_offset, std::nullopt, Offset);
1674+
if (Offset < 0)
1675+
addSInt(MemberDie, dwarf::DW_AT_bit_offset, dwarf::DW_FORM_sdata,
1676+
Offset);
1677+
else
1678+
addUInt(MemberDie, dwarf::DW_AT_bit_offset, std::nullopt,
1679+
(uint64_t)Offset);
16731680
OffsetInBytes = FieldOffset >> 3;
16741681
} else {
16751682
addUInt(MemberDie, dwarf::DW_AT_data_bit_offset, std::nullopt, Offset);

llvm/test/DebugInfo/ARM/bitfield.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
; CHECK: DW_AT_name {{.*}} "reserved"
1313
; CHECK: DW_AT_byte_size {{.*}} (0x04)
1414
; CHECK: DW_AT_bit_size {{.*}} (0x1c)
15-
; CHECK: DW_AT_bit_offset {{.*}} (0xfffffffffffffff8)
15+
; CHECK: DW_AT_bit_offset {{.*}} (-8)
1616
; CHECK: DW_AT_data_member_location {{.*}} (DW_OP_plus_uconst 0x0)
1717

1818
%struct.anon = type { i8, [5 x i8] }

llvm/test/DebugInfo/NVPTX/packed_bitfields.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
; CHECK-NEXT: .b8 1 // DW_AT_byte_size
1717
; CHECK-NEXT: .b8 6 // DW_AT_bit_size
1818
; Negative offset must be encoded as an unsigned integer.
19-
; CHECK-NEXT: .b64 0xffffffffffffffff // DW_AT_bit_offset
19+
; CHECK-NEXT: .b8 127 // DW_AT_bit_offset
2020
; CHECK-NEXT: .b8 2 // DW_AT_data_member_location
2121

2222
%struct.anon = type { i16 }

llvm/test/DebugInfo/X86/packed_bitfields.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
; CHECK-NOT: DW_TAG_member
1616
; CHECK: DW_AT_byte_size {{.*}} (0x01)
1717
; CHECK-NEXT: DW_AT_bit_size {{.*}} (0x06)
18-
; CHECK-NEXT: DW_AT_bit_offset {{.*}} (0xffffffffffffffff)
18+
; CHECK-NEXT: DW_AT_bit_offset {{.*}} (-1)
1919
; CHECK-NEXT: DW_AT_data_member_location {{.*}} ({{.*}}0x0{{0*}})
2020

2121
; ModuleID = 'repro.c'

0 commit comments

Comments
 (0)