295 lines
12 KiB
Python
295 lines
12 KiB
Python
"""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_a(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
|
|
)
|