Skip to content

Commit 997da62

Browse files
committed
Emit DIE's size in bits when size is not a multiple of 8
The existing code will always round down the size in bits when calculating the size in bytes (for example, a types with 1-7 bits will be emitted as 0 bytes long). Fix this by emitting the size in bits if the size is not aligned to a byte.
1 parent 6e574f1 commit 997da62

File tree

3 files changed

+110
-14
lines changed

3 files changed

+110
-14
lines changed

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,12 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
298298
byte_size = form_value.Unsigned();
299299
break;
300300

301+
case DW_AT_bit_size:
302+
// Convert the bit size to byte size, and round it up to the minimum
303+
// amount of bytes that will fit the bits.
304+
byte_size = (form_value.Unsigned() + 7) / 8;
305+
break;
306+
301307
case DW_AT_byte_stride:
302308
byte_stride = form_value.Unsigned();
303309
break;
@@ -2134,6 +2140,16 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos(
21342140
template_param_infos.hasParameterPack();
21352141
}
21362142

2143+
/// Reads the bit size from a die, by trying both the byte size and bit size
2144+
/// attributes.
2145+
static uint64_t GetSizeInBitsFromDie(const DWARFDIE &die) {
2146+
const uint64_t byte_size =
2147+
die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);
2148+
if (byte_size != UINT64_MAX)
2149+
return byte_size * 8;
2150+
return die.GetAttributeValueAsUnsigned(DW_AT_bit_size, UINT64_MAX);
2151+
}
2152+
21372153
bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
21382154
lldb_private::Type *type,
21392155
CompilerType &clang_type) {
@@ -2211,8 +2227,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
22112227
if (type)
22122228
layout_info.bit_size = type->GetByteSize(nullptr).value_or(0) * 8;
22132229
if (layout_info.bit_size == 0)
2214-
layout_info.bit_size =
2215-
die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8;
2230+
layout_info.bit_size = GetSizeInBitsFromDie(die);
22162231

22172232
clang::CXXRecordDecl *record_decl =
22182233
m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType());
@@ -2864,10 +2879,8 @@ void DWARFASTParserClang::ParseSingleMember(
28642879
ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
28652880
const dw_tag_t tag = die.Tag();
28662881
// Get the parent byte size so we can verify any members will fit
2867-
const uint64_t parent_byte_size =
2868-
parent_die.GetAttributeValueAsUnsigned(DW_AT_byte_size, UINT64_MAX);
2869-
const uint64_t parent_bit_size =
2870-
parent_byte_size == UINT64_MAX ? UINT64_MAX : parent_byte_size * 8;
2882+
uint64_t parent_bit_size = GetSizeInBitsFromDie(parent_die);
2883+
;
28712884

28722885
// FIXME: Remove the workarounds below and make this const.
28732886
MemberAttributes attrs(die, parent_die, module_sp);

llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,16 @@ std::string DwarfUnit::getParentContextString(const DIScope *Context) const {
687687
return CS;
688688
}
689689

690+
/// Returns the most appropriate dwarf size attribute (bits or bytes) and size
691+
/// to be used with it, given the input size in bits.
692+
static std::pair<dwarf::Attribute, uint64_t>
693+
getMostAppropriateRepresentationAndSize(uint64_t SizeInBits) {
694+
if (SizeInBits % 8 == 0) {
695+
return {dwarf::DW_AT_byte_size, SizeInBits / 8};
696+
}
697+
return {dwarf::DW_AT_bit_size, SizeInBits};
698+
}
699+
690700
void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) {
691701
// Get core information.
692702
StringRef Name = BTy->getName();
@@ -702,8 +712,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) {
702712
addUInt(Buffer, dwarf::DW_AT_encoding, dwarf::DW_FORM_data1,
703713
BTy->getEncoding());
704714

705-
uint64_t Size = BTy->getSizeInBits() >> 3;
706-
addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, Size);
715+
auto [SizeAttribute, Size] =
716+
getMostAppropriateRepresentationAndSize(BTy->getSizeInBits());
717+
addUInt(Buffer, SizeAttribute, std::nullopt, Size);
707718

708719
if (BTy->isBigEndian())
709720
addUInt(Buffer, dwarf::DW_AT_endianity, std::nullopt, dwarf::DW_END_big);
@@ -731,8 +742,9 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) {
731742
DwarfExpr.addExpression(Expr);
732743
addBlock(Buffer, dwarf::DW_AT_string_length, DwarfExpr.finalize());
733744
} else {
734-
uint64_t Size = STy->getSizeInBits() >> 3;
735-
addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, Size);
745+
auto [SizeAttributte, Size] =
746+
getMostAppropriateRepresentationAndSize(STy->getSizeInBits());
747+
addUInt(Buffer, SizeAttributte, std::nullopt, Size);
736748
}
737749

738750
if (DIExpression *Expr = STy->getStringLocationExp()) {
@@ -755,7 +767,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) {
755767
void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
756768
// Get core information.
757769
StringRef Name = DTy->getName();
758-
uint64_t Size = DTy->getSizeInBits() >> 3;
770+
auto [SizeAttribute, Size] =
771+
getMostAppropriateRepresentationAndSize(DTy->getSizeInBits());
759772
uint16_t Tag = Buffer.getTag();
760773

761774
// Map to main type, void will not have a type.
@@ -783,7 +796,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) {
783796
&& Tag != dwarf::DW_TAG_ptr_to_member_type
784797
&& Tag != dwarf::DW_TAG_reference_type
785798
&& Tag != dwarf::DW_TAG_rvalue_reference_type)
786-
addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, Size);
799+
addUInt(Buffer, SizeAttribute, std::nullopt, Size);
787800

788801
if (Tag == dwarf::DW_TAG_ptr_to_member_type)
789802
addDIEEntry(Buffer, dwarf::DW_AT_containing_type,
@@ -873,7 +886,8 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
873886
// Add name if not anonymous or intermediate type.
874887
StringRef Name = CTy->getName();
875888

876-
uint64_t Size = CTy->getSizeInBits() >> 3;
889+
auto [SizeAttribute, Size] =
890+
getMostAppropriateRepresentationAndSize(CTy->getSizeInBits());
877891
uint16_t Tag = Buffer.getTag();
878892

879893
switch (Tag) {
@@ -1017,7 +1031,7 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DICompositeType *CTy) {
10171031
// TODO: Do we care about size for enum forward declarations?
10181032
if (Size &&
10191033
(!CTy->isForwardDecl() || Tag == dwarf::DW_TAG_enumeration_type))
1020-
addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, Size);
1034+
addUInt(Buffer, SizeAttribute, std::nullopt, Size);
10211035
else if (!CTy->isForwardDecl())
10221036
// Add zero size if it is not a forward declaration.
10231037
addUInt(Buffer, dwarf::DW_AT_byte_size, std::nullopt, 0);
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
; RUN: llc -mtriple arm64-apple-darwin -filetype=obj %s -o %t
2+
; RUN: llvm-dwarfdump -all %t | FileCheck %s
3+
4+
; Checks that bit sizes that are not byte aligned are rounded up.
5+
6+
; Check that a 1 bit sized type gets emitted as 1 bit long.
7+
; CHECK: DW_AT_name ("one_bit_int")
8+
; CHECK-NEXT: DW_AT_encoding (DW_ATE_signed)
9+
; CHECK-NEXT: DW_AT_bit_size (0x01)
10+
11+
; Check that a 9 bit sized type gets emitted as 2 bytes long.
12+
; CHECK: DW_AT_name ("nine_bit_double")
13+
; CHECK-NEXT: DW_AT_encoding (DW_ATE_float)
14+
; CHECK-NEXT: DW_AT_bit_size (0x09)
15+
16+
; Check that a 7 bit sized type gets emitted as 1 bytes long.
17+
; CHECK: DW_AT_name ("seven_bit_float")
18+
; CHECK-NEXT: DW_AT_encoding (DW_ATE_float)
19+
; CHECK-NEXT: DW_AT_bit_size (0x07)
20+
21+
; Check that a byte aligned bit size is emitted with the same byte size.
22+
; CHECK: DW_AT_name ("four_byte_S")
23+
; CHECK-NEXT: DW_AT_byte_size (0x04)
24+
25+
%struct.S = type { i32 }
26+
27+
; Function Attrs: noinline nounwind optnone ssp uwtable(sync)
28+
define void @func(i32 noundef %a, double noundef %b, float noundef %c, i64 %s.coerce) !dbg !10 {
29+
entry:
30+
%s = alloca %struct.S, align 4
31+
%a.addr = alloca i32, align 4
32+
%b.addr = alloca double, align 8
33+
%c.addr = alloca float, align 4
34+
call void @llvm.dbg.declare(metadata ptr %a.addr, metadata !20, metadata !DIExpression()), !dbg !21
35+
call void @llvm.dbg.declare(metadata ptr %b.addr, metadata !22, metadata !DIExpression()), !dbg !23
36+
call void @llvm.dbg.declare(metadata ptr %c.addr, metadata !24, metadata !DIExpression()), !dbg !25
37+
call void @llvm.dbg.declare(metadata ptr %s, metadata !26, metadata !DIExpression()), !dbg !27
38+
ret void, !dbg !28
39+
}
40+
41+
; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
42+
declare void @llvm.dbg.declare(metadata, metadata, metadata)
43+
44+
!llvm.module.flags = !{!2}
45+
!llvm.dbg.cu = !{!7}
46+
47+
!2 = !{i32 2, !"Debug Info Version", i32 3}
48+
!7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !8, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
49+
!8 = !DIFile(filename: "t.c", directory: "")
50+
!10 = distinct !DISubprogram(name: "func", scope: !8, file: !8, line: 6, type: !11, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !19)
51+
!11 = !DISubroutineType(types: !12)
52+
!12 = !{null, !13, !14, !15, !16}
53+
!13 = !DIBasicType(name: "one_bit_int", size: 1, encoding: DW_ATE_signed)
54+
!14 = !DIBasicType(name: "nine_bit_double", size: 9, encoding: DW_ATE_float)
55+
!15 = !DIBasicType(name: "seven_bit_float", size: 7, encoding: DW_ATE_float)
56+
!16 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "four_byte_S", file: !8, line: 2, size: 32, elements: !17)
57+
!17 = !{!18}
58+
!18 = !DIDerivedType(tag: DW_TAG_member, name: "field", scope: !16, file: !8, line: 3, baseType: !13, size: 32)
59+
!19 = !{}
60+
!20 = !DILocalVariable(name: "a", arg: 1, scope: !10, file: !8, line: 6, type: !13)
61+
!21 = !DILocation(line: 6, column: 15, scope: !10)
62+
!22 = !DILocalVariable(name: "b", arg: 2, scope: !10, file: !8, line: 6, type: !14)
63+
!23 = !DILocation(line: 6, column: 25, scope: !10)
64+
!24 = !DILocalVariable(name: "c", arg: 3, scope: !10, file: !8, line: 6, type: !15)
65+
!25 = !DILocation(line: 6, column: 34, scope: !10)
66+
!26 = !DILocalVariable(name: "s", arg: 4, scope: !10, file: !8, line: 6, type: !16)
67+
!27 = !DILocation(line: 6, column: 46, scope: !10)
68+
!28 = !DILocation(line: 7, column: 1, scope: !10)
69+

0 commit comments

Comments
 (0)