| """Test that lldb recognizes enum structs emitted by Rust compiler """ |
| import logging |
| |
| import lldb |
| from lldbsuite.test.decorators import * |
| from lldbsuite.test.lldbtest import * |
| from RustEnumValue import RustEnumValue |
| |
| |
| class TestRustEnumStructs(TestBase): |
| def setUp(self): |
| TestBase.setUp(self) |
| src_dir = self.getSourceDir() |
| yaml_path = os.path.join(src_dir, "main.yaml") |
| obj_path = self.getBuildArtifact("main.o") |
| self.yaml2obj(yaml_path, obj_path) |
| self.dbg.CreateTarget(obj_path) |
| |
| def getFromGlobal(self, name): |
| values = self.target().FindGlobalVariables(name, 1) |
| self.assertEqual(values.GetSize(), 1) |
| return RustEnumValue(values[0]) |
| |
| def test_clike_enums_are_represented_correctly(self): |
| # these type of enums are not using DW_TAG_variant_part. |
| all_values = [ |
| self.target().FindFirstGlobalVariable("CLIKE_DEFAULT_A").GetValue(), |
| self.target().FindFirstGlobalVariable("CLIKE_DEFAULT_B").GetValue(), |
| self.target().FindFirstGlobalVariable("CLIKE_U8_A").GetValue(), |
| self.target().FindFirstGlobalVariable("CLIKE_U8_C").GetValue(), |
| self.target().FindFirstGlobalVariable("CLIKE_U32_A").GetValue(), |
| self.target().FindFirstGlobalVariable("CLIKE_U32_B").GetValue(), |
| ] |
| self.assertEqual( |
| all_values, ["A", "B", "VariantA", "VariantC", "VariantA", "VariantB"] |
| ) |
| |
| def test_enum_with_tuples_has_all_variants(self): |
| self.assertEqual( |
| self.getFromGlobal("ENUM_WITH_TUPLES_A").getAllVariantTypes(), |
| [ |
| "main::EnumWithTuples::A:8", |
| "main::EnumWithTuples::B:8", |
| "main::EnumWithTuples::C:8", |
| "main::EnumWithTuples::D:8", |
| "main::EnumWithTuples::AA:8", |
| "main::EnumWithTuples::BB:8", |
| "main::EnumWithTuples::BC:8", |
| "main::EnumWithTuples::CC:8", |
| ], |
| ) |
| |
| def test_enum_with_tuples_values_are_correct_a(self): |
| # static ENUM_WITH_TUPLES_A: EnumWithTuples = EnumWithTuples::A(13); |
| self.assertEqual( |
| self.getFromGlobal("ENUM_WITH_TUPLES_A") |
| .getCurrentValue() |
| .GetChildAtIndex(0) |
| .GetData() |
| .GetUnsignedInt8(lldb.SBError(), 0), |
| 13, |
| ) |
| |
| def test_enum_with_tuples_values_are_correct_aa(self): |
| # static ENUM_WITH_TUPLES_AA: EnumWithTuples = EnumWithTuples::AA(13, 37); |
| value = self.getFromGlobal("ENUM_WITH_TUPLES_AA").getCurrentValue() |
| self.assertEqual( |
| ( |
| value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), |
| value.GetChildAtIndex(1).GetData().GetUnsignedInt8(lldb.SBError(), 0), |
| ), |
| (13, 37), |
| ) |
| |
| def test_enum_with_tuples_values_are_correct_b(self): |
| # static ENUM_WITH_TUPLES_B: EnumWithTuples = EnumWithTuples::B(37); |
| self.assertEqual( |
| self.getFromGlobal("ENUM_WITH_TUPLES_B") |
| .getCurrentValue() |
| .GetChildAtIndex(0) |
| .GetData() |
| .GetUnsignedInt16(lldb.SBError(), 0), |
| 37, |
| ) |
| |
| def test_enum_with_tuples_values_are_correct_bb(self): |
| # static ENUM_WITH_TUPLES_BB: EnumWithTuples = EnumWithTuples::BB(37, 5535); |
| value = self.getFromGlobal("ENUM_WITH_TUPLES_BB").getCurrentValue() |
| self.assertEqual( |
| ( |
| value.GetChildAtIndex(0).GetData().GetUnsignedInt16(lldb.SBError(), 0), |
| value.GetChildAtIndex(1).GetData().GetUnsignedInt16(lldb.SBError(), 0), |
| ), |
| (37, 5535), |
| ) |
| |
| def test_enum_with_tuples_values_are_correct_bc(self): |
| # static ENUM_WITH_TUPLES_BC: EnumWithTuples = EnumWithTuples::BC(65000, 165000); |
| value = self.getFromGlobal("ENUM_WITH_TUPLES_BC").getCurrentValue() |
| self.assertEqual( |
| ( |
| value.GetChildAtIndex(0).GetData().GetUnsignedInt16(lldb.SBError(), 0), |
| value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0), |
| ), |
| (65000, 165000), |
| ) |
| |
| def test_enum_with_tuples_values_are_correct_c(self): |
| # static ENUM_WITH_TUPLES_C: EnumWithTuples = EnumWithTuples::C(31337); |
| self.assertEqual( |
| self.getFromGlobal("ENUM_WITH_TUPLES_C") |
| .getCurrentValue() |
| .GetChildAtIndex(0) |
| .GetData() |
| .GetUnsignedInt32(lldb.SBError(), 0), |
| 31337, |
| ) |
| |
| def test_enum_with_tuples_values_are_correct_cc(self): |
| # static ENUM_WITH_TUPLES_CC: EnumWithTuples = EnumWithTuples::CC(31337, 87236); |
| value = self.getFromGlobal("ENUM_WITH_TUPLES_CC").getCurrentValue() |
| self.assertEqual( |
| ( |
| value.GetChildAtIndex(0).GetData().GetUnsignedInt32(lldb.SBError(), 0), |
| value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0), |
| ), |
| (31337, 87236), |
| ) |
| |
| def test_enum_with_tuples_values_are_correct_d(self): |
| # static ENUM_WITH_TUPLES_D: EnumWithTuples = EnumWithTuples::D(123456789012345678); |
| self.assertEqual( |
| self.getFromGlobal("ENUM_WITH_TUPLES_D") |
| .getCurrentValue() |
| .GetChildAtIndex(0) |
| .GetData() |
| .GetUnsignedInt64(lldb.SBError(), 0), |
| 123456789012345678, |
| ) |
| |
| def test_mixed_enum_variants(self): |
| # static MIXED_ENUM_A: MixedEnum1 = MixedEnum1::A; |
| self.assertEqual( |
| self.getFromGlobal("MIXED_ENUM_A").getAllVariantTypes(), |
| [ |
| "main::MixedEnum::A:64", |
| "main::MixedEnum::B:64", |
| "main::MixedEnum::C:64", |
| "main::MixedEnum::D:64", |
| "main::MixedEnum::E:64", |
| ], |
| ) |
| |
| def test_mixed_enum_a(self): |
| # static MIXED_ENUM_A: MixedEnum = MixedEnum::A; |
| value = self.getFromGlobal("MIXED_ENUM_A").getCurrentValue() |
| self.assertEqual(value.GetType().GetDisplayTypeName(), "main::MixedEnum::A") |
| self.assertEqual(value.GetValue(), None) |
| |
| def test_mixed_enum_c(self): |
| # static MIXED_ENUM_C: MixedEnum = MixedEnum::C(254, -254); |
| value = self.getFromGlobal("MIXED_ENUM_C").getCurrentValue() |
| self.assertEqual( |
| ( |
| value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), |
| value.GetChildAtIndex(1).GetData().GetSignedInt32(lldb.SBError(), 0), |
| ), |
| (254, -254), |
| ) |
| |
| def test_mixed_enum_d_none(self): |
| # static MIXED_ENUM_D_NONE: MixedEnum = MixedEnum::D(None); |
| value = RustEnumValue( |
| self.getFromGlobal("MIXED_ENUM_D_NONE").getCurrentValue().GetChildAtIndex(0) |
| ) |
| self.assertEqual( |
| value.getAllVariantTypes(), |
| [ |
| "core::option::Option<main::Struct2>::None<main::Struct2>:32", |
| "core::option::Option<main::Struct2>::Some<main::Struct2>:32", |
| ], |
| ) |
| self.assertEqual(value.getCurrentValue().GetValue(), None) |
| self.assertEqual( |
| value.getCurrentValue().GetType().GetDisplayTypeName(), |
| "core::option::Option<main::Struct2>::None<main::Struct2>", |
| ) |
| |
| def test_mixed_enum_d_some(self): |
| # static MIXED_ENUM_D_SOME: MixedEnum = MixedEnum::D(Some(Struct2 { |
| # field: 123456, |
| # inner: Struct1 { field: 123 }, |
| # })); |
| variant_with_option = RustEnumValue( |
| self.getFromGlobal("MIXED_ENUM_D_SOME").getCurrentValue().GetChildAtIndex(0) |
| ) |
| |
| value_inside_option = variant_with_option.getCurrentValue().GetChildAtIndex(0) |
| self.assertEqual( |
| value_inside_option.GetChildMemberWithName("field") |
| .GetData() |
| .GetUnsignedInt32(lldb.SBError(), 0), |
| 123456, |
| ) |
| |
| self.assertEqual( |
| value_inside_option.GetChildMemberWithName("inner") |
| .GetChildMemberWithName("field") |
| .GetData() |
| .GetSignedInt32(lldb.SBError(), 0), |
| 123, |
| ) |
| self.assertEqual( |
| value_inside_option.GetType().GetDisplayTypeName(), "main::Struct2" |
| ) |
| |
| def test_option_non_null_some_pointer(self): |
| type = self.target().FindFirstType( |
| "core::option::Option<core::ptr::non_null::NonNull<u64>>" |
| ) |
| # this type is "optimized" by rust compiler so the discriminant isn't present on Some variant of option |
| data = [1337] |
| pointer_size = self.target().GetAddressByteSize() |
| byte_order = self.target().GetByteOrder() |
| value = RustEnumValue( |
| self.target().CreateValueFromData( |
| "adhoc_value", |
| lldb.SBData.CreateDataFromUInt64Array(byte_order, pointer_size, data), |
| type, |
| ) |
| ) |
| self.assertEqual(value.getFields(), ["$variant$0", "$variant$"]) |
| self.assertEqual( |
| value.getCurrentValue() |
| .GetChildAtIndex(0) |
| .GetChildMemberWithName("pointer") |
| .GetValueAsUnsigned(), |
| 1337, |
| ) |
| |
| def test_option_non_null_none(self): |
| type = self.target().FindFirstType( |
| "core::option::Option<core::ptr::non_null::NonNull<u64>>" |
| ) |
| # this type is "optimized" by rust compiler so the discriminant isn't present on Some variant of option |
| # in this test case 0 is used to represent 'None' |
| data = [0] |
| pointer_size = self.target().GetAddressByteSize() |
| byte_order = self.target().GetByteOrder() |
| value = RustEnumValue( |
| self.target().CreateValueFromData( |
| "adhoc_value", |
| lldb.SBData.CreateDataFromUInt64Array(byte_order, pointer_size, data), |
| type, |
| ) |
| ) |
| self.assertEqual(value.getFields(), ["$variant$0", "$variant$"]) |
| self.assertEqual(value.getCurrentValue().GetValue(), None) |
| self.assertEqual( |
| value.getCurrentValue().GetType().GetDisplayTypeName(), |
| "core::option::Option<core::ptr::non_null::NonNull<u64>>::None<core::ptr::non_null::NonNull<unsigned long> >", |
| ) |
| |
| def test_niche_layout_with_fields_2(self): |
| # static NICHE_W_FIELDS_2_A: NicheLayoutWithFields2 = |
| # NicheLayoutWithFields2::A(NonZeroU32::new(800).unwrap(), 900); |
| value = self.getFromGlobal("NICHE_W_FIELDS_2_A").getCurrentValue() |
| self.assertEqual( |
| ( |
| value.GetChildAtIndex(0) |
| .GetChildAtIndex(0) |
| .GetData() |
| .GetUnsignedInt32(lldb.SBError(), 0), |
| value.GetChildAtIndex(1).GetData().GetUnsignedInt32(lldb.SBError(), 0), |
| ), |
| (800, 900), |
| ) |
| |
| def test_niche_layout_with_fields_3_a(self): |
| # static NICHE_W_FIELDS_3_A: NicheLayoutWithFields3 = NicheLayoutWithFields3::A(137, true); |
| value = self.getFromGlobal("NICHE_W_FIELDS_3_A").getCurrentValue() |
| self.assertEqual( |
| ( |
| value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), |
| value.GetChildAtIndex(1).GetData().GetUnsignedInt8(lldb.SBError(), 0), |
| ), |
| (137, 1), |
| ) |
| |
| def test_niche_layout_with_fields_3_c(self): |
| # static NICHE_W_FIELDS_3_C: NicheLayoutWithFields3 = NicheLayoutWithFields3::C(false); |
| value = self.getFromGlobal("NICHE_W_FIELDS_3_C").getCurrentValue() |
| self.assertEqual( |
| value.GetChildAtIndex(0).GetData().GetUnsignedInt8(lldb.SBError(), 0), 0 |
| ) |