1"""Test that lldb recognizes enum structs emitted by Rust compiler """ 2import logging 3 4import lldb 5from lldbsuite.test.decorators import * 6from lldbsuite.test.lldbtest import * 7from RustEnumValue import RustEnumValue 8 9 10class TestRustEnumStructs(TestBase): 11 def setUp(self): 12 TestBase.setUp(self) 13 src_dir = self.getSourceDir() 14 yaml_path = os.path.join(src_dir, "main.yaml") 15 obj_path = self.getBuildArtifact("main.o") 16 self.yaml2obj(yaml_path, obj_path) 17 self.dbg.CreateTarget(obj_path) 18 19 def getFromGlobal(self, name): 20 values = self.target().FindGlobalVariables(name, 1) 21 self.assertEqual(values.GetSize(), 1) 22 return RustEnumValue(values[0]) 23 24 def test_clike_enums_are_represented_correctly(self): 25 # these type of enums are not using DW_TAG_variant_part. 26 all_values = [ 27 self.target().FindFirstGlobalVariable("CLIKE_DEFAULT_A").GetValue(), 28 self.target().FindFirstGlobalVariable("CLIKE_DEFAULT_B").GetValue(), 29 self.target().FindFirstGlobalVariable("CLIKE_U8_A").GetValue(), 30 self.target().FindFirstGlobalVariable("CLIKE_U8_C").GetValue(), 31 self.target().FindFirstGlobalVariable("CLIKE_U32_A").GetValue(), 32 self.target().FindFirstGlobalVariable("CLIKE_U32_B").GetValue(), 33 ] 34 self.assertEqual( 35 all_values, ["A", "B", "VariantA", "VariantC", "VariantA", "VariantB"] 36 ) 37 38 def test_enum_with_tuples_has_all_variants(self): 39 self.assertEqual( 40 self.getFromGlobal("ENUM_WITH_TUPLES_A").getAllVariantTypes(), 41 [ 42 "main::EnumWithTuples::A:8", 43 "main::EnumWithTuples::B:8", 44 "main::EnumWithTuples::C:8", 45 "main::EnumWithTuples::D:8", 46 "main::EnumWithTuples::AA:8", 47 "main::EnumWithTuples::BB:8", 48 "main::EnumWithTuples::BC:8", 49 "main::EnumWithTuples::CC:8", 50 ], 51 ) 52 53 def test_enum_with_tuples_values_are_correct_a(self): 54 # static ENUM_WITH_TUPLES_A: EnumWithTuples = EnumWithTuples::A(13); 55 self.assertEqual( 56 self.getFromGlobal("ENUM_WITH_TUPLES_A") 57 .getCurrentValue() 58 .GetChildAtIndex(0) 59 .GetData() 60 .GetUnsignedInt8(lldb.SBError(), 0), 61 13, 62 ) 63 64 def test_enum_with_tuples_values_are_correct_aa(self): 65 # static ENUM_WITH_TUPLES_AA: EnumWithTuples = EnumWithTuples::AA(13, 37); 66 value = self.getFromGlobal("ENUM_WITH_TUPLES_AA").getCurrentValue() 67 self.assertEqual( 68 ( 69 value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), 70 value.GetChildAtIndex(1).GetData().GetUnsignedInt8(lldb.SBError(), 0), 71 ), 72 (13, 37), 73 ) 74 75 def test_enum_with_tuples_values_are_correct_b(self): 76 # static ENUM_WITH_TUPLES_B: EnumWithTuples = EnumWithTuples::B(37); 77 self.assertEqual( 78 self.getFromGlobal("ENUM_WITH_TUPLES_B") 79 .getCurrentValue() 80 .GetChildAtIndex(0) 81 .GetData() 82 .GetUnsignedInt16(lldb.SBError(), 0), 83 37, 84 ) 85 86 def test_enum_with_tuples_values_are_correct_bb(self): 87 # static ENUM_WITH_TUPLES_BB: EnumWithTuples = EnumWithTuples::BB(37, 5535); 88 value = self.getFromGlobal("ENUM_WITH_TUPLES_BB").getCurrentValue() 89 self.assertEqual( 90 ( 91 value.GetChildAtIndex(0).GetData().GetUnsignedInt16(lldb.SBError(), 0), 92 value.GetChildAtIndex(1).GetData().GetUnsignedInt16(lldb.SBError(), 0), 93 ), 94 (37, 5535), 95 ) 96 97 def test_enum_with_tuples_values_are_correct_bc(self): 98 # static ENUM_WITH_TUPLES_BC: EnumWithTuples = EnumWithTuples::BC(65000, 165000); 99 value = self.getFromGlobal("ENUM_WITH_TUPLES_BC").getCurrentValue() 100 self.assertEqual( 101 ( 102 value.GetChildAtIndex(0).GetData().GetUnsignedInt16(lldb.SBError(), 0), 103 value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0), 104 ), 105 (65000, 165000), 106 ) 107 108 def test_enum_with_tuples_values_are_correct_c(self): 109 # static ENUM_WITH_TUPLES_C: EnumWithTuples = EnumWithTuples::C(31337); 110 self.assertEqual( 111 self.getFromGlobal("ENUM_WITH_TUPLES_C") 112 .getCurrentValue() 113 .GetChildAtIndex(0) 114 .GetData() 115 .GetUnsignedInt32(lldb.SBError(), 0), 116 31337, 117 ) 118 119 def test_enum_with_tuples_values_are_correct_cc(self): 120 # static ENUM_WITH_TUPLES_CC: EnumWithTuples = EnumWithTuples::CC(31337, 87236); 121 value = self.getFromGlobal("ENUM_WITH_TUPLES_CC").getCurrentValue() 122 self.assertEqual( 123 ( 124 value.GetChildAtIndex(0).GetData().GetUnsignedInt32(lldb.SBError(), 0), 125 value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0), 126 ), 127 (31337, 87236), 128 ) 129 130 def test_enum_with_tuples_values_are_correct_d(self): 131 # static ENUM_WITH_TUPLES_D: EnumWithTuples = EnumWithTuples::D(123456789012345678); 132 self.assertEqual( 133 self.getFromGlobal("ENUM_WITH_TUPLES_D") 134 .getCurrentValue() 135 .GetChildAtIndex(0) 136 .GetData() 137 .GetUnsignedInt64(lldb.SBError(), 0), 138 123456789012345678, 139 ) 140 141 def test_mixed_enum_variants(self): 142 # static MIXED_ENUM_A: MixedEnum1 = MixedEnum1::A; 143 self.assertEqual( 144 self.getFromGlobal("MIXED_ENUM_A").getAllVariantTypes(), 145 [ 146 "main::MixedEnum::A:64", 147 "main::MixedEnum::B:64", 148 "main::MixedEnum::C:64", 149 "main::MixedEnum::D:64", 150 "main::MixedEnum::E:64", 151 ], 152 ) 153 154 def test_mixed_enum_a(self): 155 # static MIXED_ENUM_A: MixedEnum = MixedEnum::A; 156 value = self.getFromGlobal("MIXED_ENUM_A").getCurrentValue() 157 self.assertEqual(value.GetType().GetDisplayTypeName(), "main::MixedEnum::A") 158 self.assertEqual(value.GetValue(), None) 159 160 def test_mixed_enum_c(self): 161 # static MIXED_ENUM_C: MixedEnum = MixedEnum::C(254, -254); 162 value = self.getFromGlobal("MIXED_ENUM_C").getCurrentValue() 163 self.assertEqual( 164 ( 165 value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), 166 value.GetChildAtIndex(1).GetData().GetSignedInt32(lldb.SBError(), 0), 167 ), 168 (254, -254), 169 ) 170 171 def test_mixed_enum_d_none(self): 172 # static MIXED_ENUM_D_NONE: MixedEnum = MixedEnum::D(None); 173 value = RustEnumValue( 174 self.getFromGlobal("MIXED_ENUM_D_NONE").getCurrentValue().GetChildAtIndex(0) 175 ) 176 self.assertEqual( 177 value.getAllVariantTypes(), 178 [ 179 "core::option::Option<main::Struct2>::None<main::Struct2>:32", 180 "core::option::Option<main::Struct2>::Some<main::Struct2>:32", 181 ], 182 ) 183 self.assertEqual(value.getCurrentValue().GetValue(), None) 184 self.assertEqual( 185 value.getCurrentValue().GetType().GetDisplayTypeName(), 186 "core::option::Option<main::Struct2>::None<main::Struct2>", 187 ) 188 189 def test_mixed_enum_d_some(self): 190 # static MIXED_ENUM_D_SOME: MixedEnum = MixedEnum::D(Some(Struct2 { 191 # field: 123456, 192 # inner: Struct1 { field: 123 }, 193 # })); 194 variant_with_option = RustEnumValue( 195 self.getFromGlobal("MIXED_ENUM_D_SOME").getCurrentValue().GetChildAtIndex(0) 196 ) 197 198 value_inside_option = variant_with_option.getCurrentValue().GetChildAtIndex(0) 199 self.assertEqual( 200 value_inside_option.GetChildMemberWithName("field") 201 .GetData() 202 .GetUnsignedInt32(lldb.SBError(), 0), 203 123456, 204 ) 205 206 self.assertEqual( 207 value_inside_option.GetChildMemberWithName("inner") 208 .GetChildMemberWithName("field") 209 .GetData() 210 .GetSignedInt32(lldb.SBError(), 0), 211 123, 212 ) 213 self.assertEqual( 214 value_inside_option.GetType().GetDisplayTypeName(), "main::Struct2" 215 ) 216 217 def test_option_non_null_some_pointer(self): 218 type = self.target().FindFirstType( 219 "core::option::Option<core::ptr::non_null::NonNull<u64>>" 220 ) 221 # this type is "optimized" by rust compiler so the discriminant isn't present on Some variant of option 222 data = [1337] 223 pointer_size = self.target().GetAddressByteSize() 224 byte_order = self.target().GetByteOrder() 225 value = RustEnumValue( 226 self.target().CreateValueFromData( 227 "adhoc_value", 228 lldb.SBData.CreateDataFromUInt64Array(byte_order, pointer_size, data), 229 type, 230 ) 231 ) 232 self.assertEqual(value.getFields(), ["$variant$0", "$variant$"]) 233 self.assertEqual( 234 value.getCurrentValue() 235 .GetChildAtIndex(0) 236 .GetChildMemberWithName("pointer") 237 .GetValueAsUnsigned(), 238 1337, 239 ) 240 241 def test_option_non_null_none(self): 242 type = self.target().FindFirstType( 243 "core::option::Option<core::ptr::non_null::NonNull<u64>>" 244 ) 245 # this type is "optimized" by rust compiler so the discriminant isn't present on Some variant of option 246 # in this test case 0 is used to represent 'None' 247 data = [0] 248 pointer_size = self.target().GetAddressByteSize() 249 byte_order = self.target().GetByteOrder() 250 value = RustEnumValue( 251 self.target().CreateValueFromData( 252 "adhoc_value", 253 lldb.SBData.CreateDataFromUInt64Array(byte_order, pointer_size, data), 254 type, 255 ) 256 ) 257 self.assertEqual(value.getFields(), ["$variant$0", "$variant$"]) 258 self.assertEqual(value.getCurrentValue().GetValue(), None) 259 self.assertEqual( 260 value.getCurrentValue().GetType().GetDisplayTypeName(), 261 "core::option::Option<core::ptr::non_null::NonNull<u64>>::None<core::ptr::non_null::NonNull<unsigned long> >", 262 ) 263 264 def test_niche_layout_with_fields_2(self): 265 # static NICHE_W_FIELDS_2_A: NicheLayoutWithFields2 = 266 # NicheLayoutWithFields2::A(NonZeroU32::new(800).unwrap(), 900); 267 value = self.getFromGlobal("NICHE_W_FIELDS_2_A").getCurrentValue() 268 self.assertEqual( 269 ( 270 value.GetChildAtIndex(0) 271 .GetChildAtIndex(0) 272 .GetData() 273 .GetUnsignedInt32(lldb.SBError(), 0), 274 value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0), 275 ), 276 (800, 900), 277 ) 278 279 def test_niche_layout_with_fields_3_a(self): 280 # static NICHE_W_FIELDS_3_A: NicheLayoutWithFields3 = NicheLayoutWithFields3::A(137, true); 281 value = self.getFromGlobal("NICHE_W_FIELDS_3_A").getCurrentValue() 282 self.assertEqual( 283 ( 284 value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), 285 value.GetChildAtIndex(1).GetData().GetUnsignedInt8(lldb.SBError(), 0), 286 ), 287 (137, 1), 288 ) 289 290 def test_niche_layout_with_fields_3_c(self): 291 # static NICHE_W_FIELDS_3_C: NicheLayoutWithFields3 = NicheLayoutWithFields3::C(false); 292 value = self.getFromGlobal("NICHE_W_FIELDS_3_C").getCurrentValue() 293 self.assertEqual( 294 value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), 0 295 ) 296