Skip to content

Commit 6e146c0

Browse files
committed
Auto merge of #124458 - VladimirMakaev:lldb-enum-formatter, r=Mark-Simulacrum
Implement lldb formattter for "clang encoded" enums (LLDB 18.1+) ## Summary: fixes #79530 I landed a fix last year to enable `DW_TAG_variant_part` encoding in LLDBs (https://reviews.llvm.org/D149213). This PR is a corresponding fix in synthetic formatters to decode that information. This is in no way perfect implementation but at least it improves the status quo. But most types of enums will be visible and debuggable in some way. I've also updated most of the existing tests that touch enums and re-enabled test cases based on LLDB for enums. ## Test Plan: ran tests `./x test tests/debuginfo/`. Also tested manually in LLDB CLI and LLDB VSCode ## Other Thoughs: A better approach would probably be adopting [formatters from codelldb](https://github.com/vadimcn/codelldb/blob/master/formatters/rust.py). There is some neat hack that hooks up summary provider via synthetic provider which can ultimately fix more display issues for Rust types and enums too. But getting it to work well might take more time that I have right now.
2 parents 654afe3 + 43e6600 commit 6e146c0

11 files changed

+166
-24
lines changed

src/etc/lldb_lookup.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ def synthetic_lookup(valobj, dict):
8686
return synthetic_lookup(valobj.GetChildAtIndex(discriminant), dict)
8787
if rust_type == RustType.SINGLETON_ENUM:
8888
return synthetic_lookup(valobj.GetChildAtIndex(0), dict)
89-
89+
if rust_type == RustType.ENUM:
90+
return ClangEncodedEnumProvider(valobj, dict)
9091
if rust_type == RustType.STD_VEC:
9192
return StdVecSyntheticProvider(valobj, dict)
9293
if rust_type == RustType.STD_VEC_DEQUE:

src/etc/lldb_providers.py

+52
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,58 @@ def has_children(self):
247247
# type: () -> bool
248248
return True
249249

250+
class ClangEncodedEnumProvider:
251+
"""Pretty-printer for 'clang-encoded' enums support implemented in LLDB"""
252+
DISCRIMINANT_MEMBER_NAME = "$discr$"
253+
VALUE_MEMBER_NAME = "value"
254+
255+
def __init__(self, valobj, dict):
256+
self.valobj = valobj
257+
self.update()
258+
259+
def has_children(self):
260+
return True
261+
262+
def num_children(self):
263+
if self.is_default:
264+
return 1
265+
return 2
266+
267+
def get_child_index(self, name):
268+
if name == ClangEncodedEnumProvider.VALUE_MEMBER_NAME:
269+
return 0
270+
if name == ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME:
271+
return 1
272+
return -1
273+
274+
def get_child_at_index(self, index):
275+
if index == 0:
276+
return self.variant.GetChildMemberWithName(ClangEncodedEnumProvider.VALUE_MEMBER_NAME)
277+
if index == 1:
278+
return self.variant.GetChildMemberWithName(
279+
ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME)
280+
281+
282+
def update(self):
283+
all_variants = self.valobj.GetChildAtIndex(0)
284+
index = self._getCurrentVariantIndex(all_variants)
285+
self.variant = all_variants.GetChildAtIndex(index)
286+
self.is_default = self.variant.GetIndexOfChildWithName(
287+
ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME) == -1
288+
289+
def _getCurrentVariantIndex(self, all_variants):
290+
default_index = 0
291+
for i in range(all_variants.GetNumChildren()):
292+
variant = all_variants.GetChildAtIndex(i)
293+
discr = variant.GetChildMemberWithName(
294+
ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME)
295+
if discr.IsValid():
296+
discr_unsigned_value = discr.GetValueAsUnsigned()
297+
if variant.GetName() == f"$variant${discr_unsigned_value}":
298+
return i
299+
else:
300+
default_index = i
301+
return default_index
250302

251303
class TupleSyntheticProvider:
252304
"""Pretty-printer for tuples and tuple enum variants"""

src/etc/rust_types.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class RustType(object):
6060

6161
ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$"
6262
ENUM_DISR_FIELD_NAME = "<<variant>>"
63+
ENUM_LLDB_ENCODED_VARIANTS = "$variants$"
6364

6465
STD_TYPE_TO_REGEX = {
6566
RustType.STD_STRING: STD_STRING_REGEX,
@@ -96,7 +97,11 @@ def classify_struct(name, fields):
9697
if regex.match(name):
9798
return ty
9899

99-
if fields[0].name == ENUM_DISR_FIELD_NAME:
100+
# <<variant>> is emitted by GDB while LLDB(18.1+) emits "$variants$"
101+
if (
102+
fields[0].name == ENUM_DISR_FIELD_NAME
103+
or fields[0].name == ENUM_LLDB_ENCODED_VARIANTS
104+
):
100105
return RustType.ENUM
101106

102107
if is_tuple_fields(fields):

tests/debuginfo/borrowed-enum.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Require a gdb or lldb that can read DW_TAG_variant_part.
22
//@ min-gdb-version: 8.2
3-
//@ needs-rust-lldb
3+
//@ min-lldb-version: 1800
44

55
//@ compile-flags:-g
66

@@ -23,10 +23,13 @@
2323
// lldb-command:run
2424

2525
// lldb-command:v *the_a_ref
26+
// lldbg-check:(borrowed_enum::ABC) *the_a_ref = { value = { x = 0 y = 8970181431921507452 } $discr$ = 0 }
2627
// lldbr-check:(borrowed_enum::ABC::TheA) *the_a_ref = TheA { TheA: 0, TheB: 8970181431921507452 }
2728
// lldb-command:v *the_b_ref
29+
// lldbg-check:(borrowed_enum::ABC) *the_b_ref = { value = { 0 = 0 1 = 286331153 2 = 286331153 } $discr$ = 1 }
2830
// lldbr-check:(borrowed_enum::ABC::TheB) *the_b_ref = { = 0 = 286331153 = 286331153 }
2931
// lldb-command:v *univariant_ref
32+
// lldbg-check:(borrowed_enum::Univariant) *univariant_ref = { value = { 0 = 4820353753753434 } }
3033
// lldbr-check:(borrowed_enum::Univariant) *univariant_ref = { TheOnlyCase = { = 4820353753753434 } }
3134

3235
#![allow(unused_variables)]

tests/debuginfo/coroutine-objects.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Require a gdb that can read DW_TAG_variant_part.
22
//@ min-gdb-version: 8.2
3+
//@ min-lldb-version: 1800
34

4-
// LLDB without native Rust support cannot read DW_TAG_variant_part,
5-
// so it prints nothing for coroutines. But those tests are kept to
5+
// LLDB (18.1+) now supports DW_TAG_variant_part, but there is some bug in either compiler or LLDB
6+
// with memory layout of discriminant for this particular enum
67
// ensure that LLDB won't crash at least (like #57822).
78

89
//@ compile-flags:-g
@@ -26,16 +27,7 @@
2627

2728
// lldb-command:run
2829
// lldb-command:v b
29-
// lldbg-check:(coroutine_objects::main::{coroutine_env#0}) b =
30-
// lldb-command:continue
31-
// lldb-command:v b
32-
// lldbg-check:(coroutine_objects::main::{coroutine_env#0}) b =
33-
// lldb-command:continue
34-
// lldb-command:v b
35-
// lldbg-check:(coroutine_objects::main::{coroutine_env#0}) b =
36-
// lldb-command:continue
37-
// lldb-command:v b
38-
// lldbg-check:(coroutine_objects::main::{coroutine_env#0}) b =
30+
// lldb-check:(coroutine_objects::main::{coroutine_env#0}) b = { value = { _ref__a = 0x[...] } $discr$ = ',' }
3931

4032
// === CDB TESTS ===================================================================================
4133

tests/debuginfo/enum-thinlto.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Require a gdb that can read DW_TAG_variant_part.
22
//@ min-gdb-version: 8.2
3-
3+
//@ min-lldb-version: 1800
44
//@ compile-flags:-g -Z thinlto
55

66
// === GDB TESTS ===================================================================================
@@ -15,7 +15,7 @@
1515
// lldb-command:run
1616

1717
// lldb-command:v *abc
18-
// lldbg-check:(enum_thinlto::ABC) *abc =
18+
// lldbg-check:(enum_thinlto::ABC) *abc = { value = { x = 0 y = 8970181431921507452 } $discr$ = 0 }
1919
// lldbr-check:(enum_thinlto::ABC) *abc = (x = 0, y = 8970181431921507452)
2020

2121
#![allow(unused_variables)]

tests/debuginfo/issue-57822.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
// Require a gdb that can read DW_TAG_variant_part.
55
//@ min-gdb-version: 8.2
6-
6+
//@ min-lldb-version: 1800
77
//@ compile-flags:-g
88

99
// === GDB TESTS ===================================================================================
@@ -24,7 +24,7 @@
2424
// lldbg-check:(issue_57822::main::{closure_env#1}) g = { f = { x = 1 } }
2525

2626
// lldb-command:v b
27-
// lldbg-check:(issue_57822::main::{coroutine_env#3}) b =
27+
// lldbg-check:(issue_57822::main::{coroutine_env#3}) b = { value = { a = { value = { y = 2 } $discr$ = '\x02' } } $discr$ = '\x02' }
2828

2929
#![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)]
3030
#![omit_gdb_pretty_printer_section]

tests/debuginfo/msvc-pretty-enums.rs

+80-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,84 @@
1-
//@ only-cdb
1+
//@ min-lldb-version: 1800
2+
//@ ignore-gdb
23
//@ compile-flags:-g
4+
5+
// === LLDB TESTS ==================================================================================
6+
7+
// lldb-command:run
8+
// lldb-command:v a
9+
// lldbg-check:(core::option::Option<msvc_pretty_enums::CStyleEnum>) a = { value = { 0 = Low } }
10+
11+
// lldb-command:v b
12+
// lldbg-check:(core::option::Option<msvc_pretty_enums::CStyleEnum>) b = { value = $discr$ = '\x01' }
13+
14+
// lldb-command:v c
15+
// lldbg-check:(msvc_pretty_enums::NicheLayoutEnum) c = { value = $discr$ = '\x11' }
16+
17+
// lldb-command:v d
18+
// lldbg-check:(msvc_pretty_enums::NicheLayoutEnum) d = { value = { my_data = High } }
19+
20+
// lldb-command:v e
21+
// lldbg-check:(msvc_pretty_enums::NicheLayoutEnum) e = { value = $discr$ = '\x13' }
22+
23+
// lldb-command:v h
24+
// lldbg-check:(core::option::Option<u32>) h = { value = { 0 = 12 } $discr$ = 1 }
25+
26+
// lldb-command:v i
27+
// lldbg-check:(core::option::Option<u32>) i = { value = $discr$ = 0 }
28+
29+
// lldb-command:v j
30+
// lldbg-check:(msvc_pretty_enums::CStyleEnum) j = High
31+
32+
// lldb-command:v k
33+
// lldbg-check:(core::option::Option<alloc::string::String>) k = { value = { 0 = "IAMA optional string!" { vec = size=21 { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 'o' [6] = 'p' [7] = 't' [8] = 'i' [9] = 'o' [10] = 'n' [11] = 'a' [12] = 'l' [13] = ' ' [14] = 's' [15] = 't' [16] = 'r' [17] = 'i' [18] = 'n' [19] = 'g' [20] = '!' } } } }
34+
35+
// lldb-command:v l
36+
// lldbg-check:(core::result::Result<u32, msvc_pretty_enums::Empty>) l = { value = { 0 = {} } }
37+
38+
// lldb-command:v niche128_some
39+
// lldbg-check:(core::option::Option<core::num::nonzero::NonZero<i128>>) niche128_some = { value = $discr$ = 123456 }
40+
41+
// lldb-command:v niche128_none
42+
// lldbg-check:(core::option::Option<core::num::nonzero::NonZero<i128>>) niche128_none = { value = $discr$ = 0 }
43+
44+
// lldb-command:v wrapping_niche128_untagged
45+
// lldbg-check:(msvc_pretty_enums::Wrapping128Niche) wrapping_niche128_untagged = { value = { 0 = { 0 = 340282366920938463463374607431768211454 } } }
46+
47+
// lldb-command:v wrapping_niche128_none1
48+
// lldbg-check:(msvc_pretty_enums::Wrapping128Niche) wrapping_niche128_none1 = { value = { 0 = { 0 = 2 } } }
49+
50+
// lldb-command:v direct_tag_128_a
51+
// lldbg-check:(msvc_pretty_enums::DirectTag128) direct_tag_128_a = { value = { 0 = 42 } $discr$ = 0 }
52+
53+
// lldb-command:v direct_tag_128_b
54+
// lldbg-check:(msvc_pretty_enums::DirectTag128) direct_tag_128_b = { value = { 0 = 137 } $discr$ = 1 }
55+
56+
// &u32 is incorrectly formatted and LLDB thinks it's a char* so skipping niche_w_fields_1_some
57+
58+
// lldb-command:v niche_w_fields_1_none
59+
// lldbg-check:(msvc_pretty_enums::NicheLayoutWithFields1) niche_w_fields_1_none = { value = { 0 = 99 } $discr$ = 1 }
60+
61+
// lldb-command:v niche_w_fields_2_some
62+
// lldbg-check:(msvc_pretty_enums::NicheLayoutWithFields2) niche_w_fields_2_some = { value = { 0 = 800 { __0 = { 0 = 800 } } 1 = 900 } $discr$ = 0 }
63+
64+
// lldb-command:v niche_w_fields_3_some
65+
// lldbg-check:(msvc_pretty_enums::NicheLayoutWithFields3) niche_w_fields_3_some = { value = { 0 = '\x89' 1 = true } }
66+
67+
// lldb-command:v niche_w_fields_3_niche3
68+
// lldbg-check:(msvc_pretty_enums::NicheLayoutWithFields3) niche_w_fields_3_niche3 = { value = { 0 = '"' } $discr$ = '\x04' }
69+
70+
// lldb-command:v arbitrary_discr1
71+
// lldbg-check:(msvc_pretty_enums::ArbitraryDiscr) arbitrary_discr1 = { value = { 0 = 1234 } $discr$ = 1000 }
72+
73+
// lldb-command:v arbitrary_discr2
74+
// lldbg-check:(msvc_pretty_enums::ArbitraryDiscr) arbitrary_discr2 = { value = { 0 = 5678 } $discr$ = 5000000 }
75+
76+
// === CDB TESTS ==================================================================================
77+
// cdb-command: g
78+
//
79+
// cdb-command: dx a
80+
// cdb-check:a : Some [Type: enum2$<core::option::Option<msvc_pretty_enums::CStyleEnum> >]
81+
// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum]
382
//
483
// cdb-command: g
584
//

tests/debuginfo/struct-style-enum.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Require a gdb or lldb that can read DW_TAG_variant_part.
22
//@ min-gdb-version: 8.2
3-
//@ needs-rust-lldb
4-
3+
//@ min-lldb-version: 1800
54
//@ compile-flags:-g
65

76
// === GDB TESTS ===================================================================================
@@ -27,15 +26,19 @@
2726
// lldb-command:run
2827

2928
// lldb-command:v case1
29+
// lldbg-check:(struct_style_enum::Regular) case1 = { value = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 } $discr$ = 0 }
3030
// lldbr-check:(struct_style_enum::Regular::Case1) case1 = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 }
3131

3232
// lldb-command:v case2
33+
// lldbg-check:(struct_style_enum::Regular) case2 = { value = { a = 0 b = 286331153 c = 286331153 } $discr$ = 1 }
3334
// lldbr-check:(struct_style_enum::Regular::Case2) case2 = Case2 { Case1: 0, Case2: 286331153, Case3: 286331153 }
3435

3536
// lldb-command:v case3
37+
// lldbg-check:(struct_style_enum::Regular) case3 = { value = { a = 0 b = 6438275382588823897 } $discr$ = 2 }
3638
// lldbr-check:(struct_style_enum::Regular::Case3) case3 = Case3 { Case1: 0, Case2: 6438275382588823897 }
3739

3840
// lldb-command:v univariant
41+
// lldbg-check:(struct_style_enum::Univariant) univariant = { value = { a = -1 } }
3942
// lldbr-check:(struct_style_enum::Univariant) univariant = Univariant { TheOnlyCase: TheOnlyCase { a: -1 } }
4043

4144
#![allow(unused_variables)]

tests/debuginfo/tuple-style-enum.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Require a gdb or lldb that can read DW_TAG_variant_part.
22
//@ min-gdb-version: 8.2
3-
//@ needs-rust-lldb
3+
//@ min-lldb-version: 1800
44

55
//@ compile-flags:-g
66

@@ -27,15 +27,19 @@
2727
// lldb-command:run
2828

2929
// lldb-command:v case1
30+
// lldbg-check:(tuple_style_enum::Regular) case1 = { value = { 0 = 0 1 = 31868 2 = 31868 3 = 31868 4 = 31868 } $discr$ = 0 }
3031
// lldbr-check:(tuple_style_enum::Regular::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
3132

3233
// lldb-command:v case2
34+
// lldbg-check:(tuple_style_enum::Regular) case2 = { value = { 0 = 0 1 = 286331153 2 = 286331153 } $discr$ = 1 }
3335
// lldbr-check:(tuple_style_enum::Regular::Case2) case2 = Case2 { Case1: 0, Case2: 286331153, Case3: 286331153 }
3436

3537
// lldb-command:v case3
38+
// lldbg-check:(tuple_style_enum::Regular) case3 = { value = { 0 = 0 1 = 6438275382588823897 } $discr$ = 2 }
3639
// lldbr-check:(tuple_style_enum::Regular::Case3) case3 = Case3 { Case1: 0, Case2: 6438275382588823897 }
3740

3841
// lldb-command:v univariant
42+
// lldbg-check:(tuple_style_enum::Univariant) univariant = { value = { 0 = -1 } }
3943
// lldbr-check:(tuple_style_enum::Univariant) univariant = { TheOnlyCase = { = -1 } }
4044

4145
#![allow(unused_variables)]

tests/debuginfo/unique-enum.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Require a gdb or lldb that can read DW_TAG_variant_part.
22
//@ min-gdb-version: 8.2
3-
//@ needs-rust-lldb
3+
//@ min-lldb-version: 1800
44

55
//@ compile-flags:-g
66

@@ -23,12 +23,15 @@
2323
// lldb-command:run
2424

2525
// lldb-command:v *the_a
26+
// lldbg-check:(unique_enum::ABC) *the_a = { value = { x = 0 y = 8970181431921507452 } $discr$ = 0 }
2627
// lldbr-check:(unique_enum::ABC::TheA) *the_a = TheA { TheA: 0, TheB: 8970181431921507452 }
2728

2829
// lldb-command:v *the_b
30+
// lldbg-check:(unique_enum::ABC) *the_b = { value = { 0 = 0 1 = 286331153 2 = 286331153 } $discr$ = 1 }
2931
// lldbr-check:(unique_enum::ABC::TheB) *the_b = { = 0 = 286331153 = 286331153 }
3032

3133
// lldb-command:v *univariant
34+
// lldbg-check:(unique_enum::Univariant) *univariant = { value = { 0 = 123234 } }
3235
// lldbr-check:(unique_enum::Univariant) *univariant = { TheOnlyCase = { = 123234 } }
3336

3437
#![allow(unused_variables)]

0 commit comments

Comments
 (0)