mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 17:53:07 +00:00
Add basic class type support
This implements the first step at supporting C++: class types. In particular, this adds a new drgn_type_kind, DRGN_TYPE_CLASS, and support for parsing DW_TAG_class_type from DWARF. Although classes are not valid in C, this adds support for pretty printing them, for completeness.
This commit is contained in:
parent
b49f773fe6
commit
0df2152307
@ -1112,6 +1112,10 @@ Types
|
|||||||
|
|
||||||
Union type.
|
Union type.
|
||||||
|
|
||||||
|
.. attribute:: CLASS
|
||||||
|
|
||||||
|
Class type.
|
||||||
|
|
||||||
.. attribute:: ENUM
|
.. attribute:: ENUM
|
||||||
|
|
||||||
Enumerated type.
|
Enumerated type.
|
||||||
@ -1274,6 +1278,11 @@ can be used just like types obtained from :meth:`Program.type()`.
|
|||||||
Create a new union type. It has kind :attr:`TypeKind.UNION`. Otherwise,
|
Create a new union type. It has kind :attr:`TypeKind.UNION`. Otherwise,
|
||||||
this is the same as :func:`struct_type()`.
|
this is the same as :func:`struct_type()`.
|
||||||
|
|
||||||
|
.. function:: class_type(tag, size, members, qualifiers=None)
|
||||||
|
|
||||||
|
Create a new class type. It has kind :attr:`TypeKind.CLASS`. Otherwise,
|
||||||
|
this is the same as :func:`struct_type()`.
|
||||||
|
|
||||||
.. function:: enum_type(tag, type, enumerators, qualifiers=None)
|
.. function:: enum_type(tag, type, enumerators, qualifiers=None)
|
||||||
|
|
||||||
Create a new enumerated type. It has kind :attr:`TypeKind.ENUM`.
|
Create a new enumerated type. It has kind :attr:`TypeKind.ENUM`.
|
||||||
|
@ -67,6 +67,7 @@ from _drgn import (
|
|||||||
array_type,
|
array_type,
|
||||||
bool_type,
|
bool_type,
|
||||||
cast,
|
cast,
|
||||||
|
class_type,
|
||||||
complex_type,
|
complex_type,
|
||||||
container_of,
|
container_of,
|
||||||
enum_type,
|
enum_type,
|
||||||
@ -110,6 +111,7 @@ __all__ = [
|
|||||||
'array_type',
|
'array_type',
|
||||||
'bool_type',
|
'bool_type',
|
||||||
'cast',
|
'cast',
|
||||||
|
'class_type',
|
||||||
'complex_type',
|
'complex_type',
|
||||||
'container_of',
|
'container_of',
|
||||||
'enum_type',
|
'enum_type',
|
||||||
|
@ -291,6 +291,8 @@ enum drgn_type_kind {
|
|||||||
DRGN_TYPE_STRUCT,
|
DRGN_TYPE_STRUCT,
|
||||||
/** Union type. */
|
/** Union type. */
|
||||||
DRGN_TYPE_UNION,
|
DRGN_TYPE_UNION,
|
||||||
|
/** Class type. */
|
||||||
|
DRGN_TYPE_CLASS,
|
||||||
/** Enumerated type. */
|
/** Enumerated type. */
|
||||||
DRGN_TYPE_ENUM,
|
DRGN_TYPE_ENUM,
|
||||||
/** Type definition (a.k.a.\ alias) type. */
|
/** Type definition (a.k.a.\ alias) type. */
|
||||||
@ -332,7 +334,7 @@ enum drgn_primitive_type {
|
|||||||
*/
|
*/
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
/** Member of a structure or union type. */
|
/** Member of a structure, union, or class type. */
|
||||||
struct drgn_type_member {
|
struct drgn_type_member {
|
||||||
/**
|
/**
|
||||||
* Type of the member.
|
* Type of the member.
|
||||||
@ -456,7 +458,7 @@ drgn_type_primitive(struct drgn_type *type)
|
|||||||
* Get whether a type is complete (i.e., the type definition is known).
|
* Get whether a type is complete (i.e., the type definition is known).
|
||||||
*
|
*
|
||||||
* This is always @c false for the void type. It may be @c false for structure,
|
* This is always @c false for the void type. It may be @c false for structure,
|
||||||
* union, enumerated, and array types, as well as typedef types where the
|
* union, class, enumerated, and array types, as well as typedef types where the
|
||||||
* underlying type is one of those. Otherwise, it is always @c true.
|
* underlying type is one of those. Otherwise, it is always @c true.
|
||||||
*/
|
*/
|
||||||
static inline bool drgn_type_is_complete(struct drgn_type *type)
|
static inline bool drgn_type_is_complete(struct drgn_type *type)
|
||||||
@ -492,7 +494,7 @@ static inline const char *drgn_type_name(struct drgn_type *type)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get whether a kind of type has a size. This is true for integer, boolean,
|
* Get whether a kind of type has a size. This is true for integer, boolean,
|
||||||
* floating-point, complex, structure, union, and pointer types.
|
* floating-point, complex, structure, union, class, and pointer types.
|
||||||
*/
|
*/
|
||||||
static inline bool drgn_type_kind_has_size(enum drgn_type_kind kind)
|
static inline bool drgn_type_kind_has_size(enum drgn_type_kind kind)
|
||||||
{
|
{
|
||||||
@ -502,6 +504,7 @@ static inline bool drgn_type_kind_has_size(enum drgn_type_kind kind)
|
|||||||
kind == DRGN_TYPE_COMPLEX ||
|
kind == DRGN_TYPE_COMPLEX ||
|
||||||
kind == DRGN_TYPE_STRUCT ||
|
kind == DRGN_TYPE_STRUCT ||
|
||||||
kind == DRGN_TYPE_UNION ||
|
kind == DRGN_TYPE_UNION ||
|
||||||
|
kind == DRGN_TYPE_CLASS ||
|
||||||
kind == DRGN_TYPE_POINTER);
|
kind == DRGN_TYPE_POINTER);
|
||||||
}
|
}
|
||||||
/** Get whether a type has a size. @sa drgn_type_kind_has_size() */
|
/** Get whether a type has a size. @sa drgn_type_kind_has_size() */
|
||||||
@ -542,13 +545,14 @@ static inline bool drgn_type_is_signed(struct drgn_type *type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get whether a kind of type has a tag. This is true for structure, union, and
|
* Get whether a kind of type has a tag. This is true for structure, union,
|
||||||
* enumerated types.
|
* class, and enumerated types.
|
||||||
*/
|
*/
|
||||||
static inline bool drgn_type_kind_has_tag(enum drgn_type_kind kind)
|
static inline bool drgn_type_kind_has_tag(enum drgn_type_kind kind)
|
||||||
{
|
{
|
||||||
return (kind == DRGN_TYPE_STRUCT ||
|
return (kind == DRGN_TYPE_STRUCT ||
|
||||||
kind == DRGN_TYPE_UNION ||
|
kind == DRGN_TYPE_UNION ||
|
||||||
|
kind == DRGN_TYPE_CLASS ||
|
||||||
kind == DRGN_TYPE_ENUM);
|
kind == DRGN_TYPE_ENUM);
|
||||||
}
|
}
|
||||||
/** Get whether a type has a tag. @sa drgn_type_kind_has_tag() */
|
/** Get whether a type has a tag. @sa drgn_type_kind_has_tag() */
|
||||||
@ -571,12 +575,14 @@ static inline void *drgn_type_payload(struct drgn_type *type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get whether a kind of type has members. This is true for structure and union
|
* Get whether a kind of type has members. This is true for structure, union,
|
||||||
* types.
|
* and class types.
|
||||||
*/
|
*/
|
||||||
static inline bool drgn_type_kind_has_members(enum drgn_type_kind kind)
|
static inline bool drgn_type_kind_has_members(enum drgn_type_kind kind)
|
||||||
{
|
{
|
||||||
return kind == DRGN_TYPE_STRUCT || kind == DRGN_TYPE_UNION;
|
return (kind == DRGN_TYPE_STRUCT ||
|
||||||
|
kind == DRGN_TYPE_UNION ||
|
||||||
|
kind == DRGN_TYPE_CLASS);
|
||||||
}
|
}
|
||||||
/** Get whether a type has members. @sa drgn_type_kind_has_members() */
|
/** Get whether a type has members. @sa drgn_type_kind_has_members() */
|
||||||
static inline bool drgn_type_has_members(struct drgn_type *type)
|
static inline bool drgn_type_has_members(struct drgn_type *type)
|
||||||
@ -1405,9 +1411,9 @@ enum drgn_object_kind {
|
|||||||
/**
|
/**
|
||||||
* Memory buffer.
|
* Memory buffer.
|
||||||
*
|
*
|
||||||
* This is used for objects with a complex, structure, union, or array
|
* This is used for objects with a complex, structure, union, class, or
|
||||||
* type. The value is a buffer of the contents of that object's memory
|
* array type. The value is a buffer of the contents of that object's
|
||||||
* in the program.
|
* memory in the program.
|
||||||
*/
|
*/
|
||||||
DRGN_OBJECT_BUFFER,
|
DRGN_OBJECT_BUFFER,
|
||||||
/**
|
/**
|
||||||
@ -1440,7 +1446,7 @@ enum drgn_object_kind {
|
|||||||
* Incomplete buffer value.
|
* Incomplete buffer value.
|
||||||
*
|
*
|
||||||
* This is used for reference objects with an incomplete structure,
|
* This is used for reference objects with an incomplete structure,
|
||||||
* union, or array type.
|
* union, class, or array type.
|
||||||
*/
|
*/
|
||||||
DRGN_OBJECT_INCOMPLETE_BUFFER = -2,
|
DRGN_OBJECT_INCOMPLETE_BUFFER = -2,
|
||||||
/**
|
/**
|
||||||
@ -2198,7 +2204,7 @@ drgn_object_dereference(struct drgn_object *res, const struct drgn_object *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a member of a structure or union @ref drgn_object (@c .).
|
* Get a member of a structure, union, or class @ref drgn_object (@c .).
|
||||||
*
|
*
|
||||||
* @param[out] res Returned member. May be the same as @p obj.
|
* @param[out] res Returned member. May be the same as @p obj.
|
||||||
* @param[in] obj Object.
|
* @param[in] obj Object.
|
||||||
|
@ -341,10 +341,11 @@ drgn_base_type_from_dwarf(struct drgn_dwarf_info_cache *dicache, Dwarf_Die *die,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DW_TAG_structure_type, DW_TAG_union_type, and DW_TAG_enumeration_type can be
|
* DW_TAG_structure_type, DW_TAG_union_type, DW_TAG_class_type, and
|
||||||
* incomplete (i.e., have a DW_AT_declaration of true). This tries to find the
|
* DW_TAG_enumeration_type can be incomplete (i.e., have a DW_AT_declaration of
|
||||||
* complete type. If it succeeds, it returns NULL. If it can't find a complete
|
* true). This tries to find the complete type. If it succeeds, it returns NULL.
|
||||||
* type, it returns a DRGN_ERROR_STOP error. Otherwise, it returns an error.
|
* If it can't find a complete type, it returns a DRGN_ERROR_STOP error.
|
||||||
|
* Otherwise, it returns an error.
|
||||||
*/
|
*/
|
||||||
static struct drgn_error *
|
static struct drgn_error *
|
||||||
drgn_dwarf_info_cache_find_complete(struct drgn_dwarf_info_cache *dicache,
|
drgn_dwarf_info_cache_find_complete(struct drgn_dwarf_info_cache *dicache,
|
||||||
@ -543,11 +544,13 @@ static struct drgn_error *parse_member(struct drgn_dwarf_info_cache *dicache,
|
|||||||
|
|
||||||
static struct drgn_error *
|
static struct drgn_error *
|
||||||
drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
||||||
Dwarf_Die *die, bool is_struct,
|
Dwarf_Die *die, enum drgn_type_kind kind,
|
||||||
struct drgn_type **ret, bool *should_free)
|
struct drgn_type **ret, bool *should_free)
|
||||||
{
|
{
|
||||||
struct drgn_error *err;
|
struct drgn_error *err;
|
||||||
struct drgn_type *type;
|
struct drgn_type *type;
|
||||||
|
const char *dw_tag_str;
|
||||||
|
uint64_t dw_tag;
|
||||||
Dwarf_Attribute attr_mem;
|
Dwarf_Attribute attr_mem;
|
||||||
Dwarf_Attribute *attr;
|
Dwarf_Attribute *attr;
|
||||||
const char *tag;
|
const char *tag;
|
||||||
@ -558,28 +561,43 @@ drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
|||||||
bool little_endian;
|
bool little_endian;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
case DRGN_TYPE_STRUCT:
|
||||||
|
dw_tag_str = "DW_TAG_structure_type";
|
||||||
|
dw_tag = DW_TAG_structure_type;
|
||||||
|
break;
|
||||||
|
case DRGN_TYPE_UNION:
|
||||||
|
dw_tag_str = "DW_TAG_union_type";
|
||||||
|
dw_tag = DW_TAG_union_type;
|
||||||
|
break;
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
|
dw_tag_str = "DW_TAG_class_type";
|
||||||
|
dw_tag = DW_TAG_class_type;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRGN_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
attr = dwarf_attr_integrate(die, DW_AT_name, &attr_mem);
|
attr = dwarf_attr_integrate(die, DW_AT_name, &attr_mem);
|
||||||
if (attr) {
|
if (attr) {
|
||||||
tag = dwarf_formstring(attr);
|
tag = dwarf_formstring(attr);
|
||||||
if (!tag)
|
if (!tag) {
|
||||||
return drgn_error_format(DRGN_ERROR_OTHER,
|
return drgn_error_format(DRGN_ERROR_OTHER,
|
||||||
"DW_TAG_%s_type has invalid DW_AT_name",
|
"%s has invalid DW_AT_name",
|
||||||
is_struct ? "structure" : "union");
|
dw_tag_str);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tag = NULL;
|
tag = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwarf_flag(die, DW_AT_declaration, &declaration)) {
|
if (dwarf_flag(die, DW_AT_declaration, &declaration)) {
|
||||||
return drgn_error_format(DRGN_ERROR_OTHER,
|
return drgn_error_format(DRGN_ERROR_OTHER,
|
||||||
"DW_TAG_%s_type has invalid DW_AT_declaration",
|
"%s has invalid DW_AT_declaration",
|
||||||
is_struct ? "structure" : "union");
|
dw_tag_str);
|
||||||
}
|
}
|
||||||
if (declaration && tag) {
|
if (declaration && tag) {
|
||||||
err = drgn_dwarf_info_cache_find_complete(dicache,
|
err = drgn_dwarf_info_cache_find_complete(dicache,
|
||||||
is_struct ?
|
dw_tag, tag, ret);
|
||||||
DW_TAG_structure_type :
|
|
||||||
DW_TAG_union_type,
|
|
||||||
tag, ret);
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
*should_free = false;
|
*should_free = false;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -594,10 +612,19 @@ drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
|||||||
return &drgn_enomem;
|
return &drgn_enomem;
|
||||||
|
|
||||||
if (declaration) {
|
if (declaration) {
|
||||||
if (is_struct)
|
switch (kind) {
|
||||||
|
case DRGN_TYPE_STRUCT:
|
||||||
drgn_struct_type_init_incomplete(type, tag);
|
drgn_struct_type_init_incomplete(type, tag);
|
||||||
else
|
break;
|
||||||
|
case DRGN_TYPE_UNION:
|
||||||
drgn_union_type_init_incomplete(type, tag);
|
drgn_union_type_init_incomplete(type, tag);
|
||||||
|
break;
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
|
drgn_class_type_init_incomplete(type, tag);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRGN_UNREACHABLE();
|
||||||
|
}
|
||||||
*ret = type;
|
*ret = type;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -605,8 +632,8 @@ drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
|||||||
size = dwarf_bytesize(die);
|
size = dwarf_bytesize(die);
|
||||||
if (size == -1) {
|
if (size == -1) {
|
||||||
err = drgn_error_format(DRGN_ERROR_OTHER,
|
err = drgn_error_format(DRGN_ERROR_OTHER,
|
||||||
"DW_TAG_%s_type has missing or invalid DW_AT_byte_size",
|
"%s has missing or invalid DW_AT_byte_size",
|
||||||
is_struct ? "structure" : "union");
|
dw_tag_str);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,8 +672,13 @@ drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
|||||||
sizeof(struct drgn_type_member));
|
sizeof(struct drgn_type_member));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_struct) {
|
if (kind == DRGN_TYPE_UNION) {
|
||||||
|
drgn_union_type_init(type, tag, size, num_members);
|
||||||
|
} else {
|
||||||
|
if (kind == DRGN_TYPE_STRUCT)
|
||||||
drgn_struct_type_init(type, tag, size, num_members);
|
drgn_struct_type_init(type, tag, size, num_members);
|
||||||
|
else
|
||||||
|
drgn_class_type_init(type, tag, size, num_members);
|
||||||
/*
|
/*
|
||||||
* Flexible array members are only allowed as the last member of
|
* Flexible array members are only allowed as the last member of
|
||||||
* a structure with more than one named member. We defaulted
|
* a structure with more than one named member. We defaulted
|
||||||
@ -671,8 +703,6 @@ drgn_compound_type_from_dwarf(struct drgn_dwarf_info_cache *dicache,
|
|||||||
thunk->can_be_incomplete_array = true;
|
thunk->can_be_incomplete_array = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
drgn_union_type_init(type, tag, size, num_members);
|
|
||||||
}
|
}
|
||||||
*ret = type;
|
*ret = type;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1289,13 +1319,19 @@ drgn_type_from_dwarf_internal(struct drgn_dwarf_info_cache *dicache,
|
|||||||
err = drgn_base_type_from_dwarf(dicache, die, &ret->type);
|
err = drgn_base_type_from_dwarf(dicache, die, &ret->type);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_structure_type:
|
case DW_TAG_structure_type:
|
||||||
err = drgn_compound_type_from_dwarf(dicache, die, true,
|
err = drgn_compound_type_from_dwarf(dicache, die,
|
||||||
|
DRGN_TYPE_STRUCT,
|
||||||
&ret->type,
|
&ret->type,
|
||||||
&entry.value.should_free);
|
&entry.value.should_free);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_union_type:
|
case DW_TAG_union_type:
|
||||||
err = drgn_compound_type_from_dwarf(dicache, die, false,
|
err = drgn_compound_type_from_dwarf(dicache, die,
|
||||||
&ret->type,
|
DRGN_TYPE_UNION, &ret->type,
|
||||||
|
&entry.value.should_free);
|
||||||
|
break;
|
||||||
|
case DW_TAG_class_type:
|
||||||
|
err = drgn_compound_type_from_dwarf(dicache, die,
|
||||||
|
DRGN_TYPE_CLASS, &ret->type,
|
||||||
&entry.value.should_free);
|
&entry.value.should_free);
|
||||||
break;
|
break;
|
||||||
case DW_TAG_enumeration_type:
|
case DW_TAG_enumeration_type:
|
||||||
@ -1375,6 +1411,9 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
|
|||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
tag = DW_TAG_union_type;
|
tag = DW_TAG_union_type;
|
||||||
break;
|
break;
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
|
tag = DW_TAG_class_type;
|
||||||
|
break;
|
||||||
case DRGN_TYPE_ENUM:
|
case DRGN_TYPE_ENUM:
|
||||||
tag = DW_TAG_enumeration_type;
|
tag = DW_TAG_enumeration_type;
|
||||||
break;
|
break;
|
||||||
|
@ -115,6 +115,9 @@ c_append_tagged_name(struct drgn_qualified_type qualified_type, size_t indent,
|
|||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
keyword = "union";
|
keyword = "union";
|
||||||
break;
|
break;
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
|
keyword = "class";
|
||||||
|
break;
|
||||||
case DRGN_TYPE_ENUM:
|
case DRGN_TYPE_ENUM:
|
||||||
keyword = "enum";
|
keyword = "enum";
|
||||||
break;
|
break;
|
||||||
@ -338,6 +341,7 @@ c_declare_variable(struct drgn_qualified_type qualified_type,
|
|||||||
return c_declare_basic(qualified_type, name, indent, sb);
|
return c_declare_basic(qualified_type, name, indent, sb);
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
case DRGN_TYPE_ENUM:
|
case DRGN_TYPE_ENUM:
|
||||||
return c_declare_tagged(qualified_type, name, indent, sb);
|
return c_declare_tagged(qualified_type, name, indent, sb);
|
||||||
case DRGN_TYPE_POINTER:
|
case DRGN_TYPE_POINTER:
|
||||||
@ -488,6 +492,7 @@ c_define_type(struct drgn_qualified_type qualified_type, size_t indent,
|
|||||||
return c_declare_basic(qualified_type, NULL, indent, sb);
|
return c_declare_basic(qualified_type, NULL, indent, sb);
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
return c_define_compound(qualified_type, indent, sb);
|
return c_define_compound(qualified_type, indent, sb);
|
||||||
case DRGN_TYPE_ENUM:
|
case DRGN_TYPE_ENUM:
|
||||||
return c_define_enum(qualified_type, indent, sb);
|
return c_define_enum(qualified_type, indent, sb);
|
||||||
@ -714,10 +719,24 @@ c_pretty_print_compound_object(const struct drgn_object *obj,
|
|||||||
struct drgn_object member;
|
struct drgn_object member;
|
||||||
|
|
||||||
if (!drgn_type_is_complete(underlying_type)) {
|
if (!drgn_type_is_complete(underlying_type)) {
|
||||||
|
const char *keyword;
|
||||||
|
|
||||||
|
switch (drgn_type_kind(underlying_type)) {
|
||||||
|
case DRGN_TYPE_STRUCT:
|
||||||
|
keyword = "struct";
|
||||||
|
break;
|
||||||
|
case DRGN_TYPE_UNION:
|
||||||
|
keyword = "union";
|
||||||
|
break;
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
|
keyword = "class";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRGN_UNREACHABLE();
|
||||||
|
}
|
||||||
return drgn_error_format(DRGN_ERROR_TYPE,
|
return drgn_error_format(DRGN_ERROR_TYPE,
|
||||||
"cannot format incomplete %s object",
|
"cannot format incomplete %s object",
|
||||||
drgn_type_kind(underlying_type) ==
|
keyword);
|
||||||
DRGN_TYPE_STRUCT ? "struct" : "union");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string_builder_appendc(sb, '{'))
|
if (!string_builder_appendc(sb, '{'))
|
||||||
@ -1246,6 +1265,7 @@ c_pretty_print_object_impl(const struct drgn_object *obj, bool cast,
|
|||||||
"complex object formatting is not implemented");
|
"complex object formatting is not implemented");
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
return c_pretty_print_compound_object(obj, underlying_type,
|
return c_pretty_print_compound_object(obj, underlying_type,
|
||||||
indent,
|
indent,
|
||||||
multi_line_columns, sb);
|
multi_line_columns, sb);
|
||||||
|
@ -1040,6 +1040,7 @@ struct drgn_error *drgn_object_truthiness(const struct drgn_object *obj,
|
|||||||
switch (drgn_type_kind(underlying_type)) {
|
switch (drgn_type_kind(underlying_type)) {
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
err = drgn_object_compound_truthiness(obj,
|
err = drgn_object_compound_truthiness(obj,
|
||||||
underlying_type);
|
underlying_type);
|
||||||
if (!err || err->code == DRGN_ERROR_STOP) {
|
if (!err || err->code == DRGN_ERROR_STOP) {
|
||||||
@ -1375,7 +1376,7 @@ struct drgn_error *drgn_object_member_dereference(struct drgn_object *res,
|
|||||||
|
|
||||||
underlying_type = drgn_underlying_type(obj->type);
|
underlying_type = drgn_underlying_type(obj->type);
|
||||||
if (drgn_type_kind(underlying_type) != DRGN_TYPE_POINTER) {
|
if (drgn_type_kind(underlying_type) != DRGN_TYPE_POINTER) {
|
||||||
return drgn_type_error("'%s' is not a pointer to a structure or union",
|
return drgn_type_error("'%s' is not a pointer to a structure, union, or class",
|
||||||
obj->type);
|
obj->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@
|
|||||||
/**
|
/**
|
||||||
* Get the truthiness of an object.
|
* Get the truthiness of an object.
|
||||||
*
|
*
|
||||||
* For a signed, unsigned, or floating-point value, this is true iff the value
|
* For a signed, unsigned, or floating-point values, this is true iff the value
|
||||||
* is non-zero. For structures and unions, this is true iff it is true for any
|
* is non-zero. For structures, unions, and classes, this is true iff it is true
|
||||||
* of its members. For arrays, this is true iff it is true for any of its
|
* for any of its members. For arrays, this is true iff it is true for any of
|
||||||
* elements.
|
* its elements.
|
||||||
*/
|
*/
|
||||||
struct drgn_error *drgn_object_truthiness(const struct drgn_object *obj,
|
struct drgn_error *drgn_object_truthiness(const struct drgn_object *obj,
|
||||||
bool *ret);
|
bool *ret);
|
||||||
|
@ -178,6 +178,7 @@ DrgnType *float_type(PyObject *self, PyObject *args, PyObject *kwds);
|
|||||||
DrgnType *complex_type(PyObject *self, PyObject *args, PyObject *kwds);
|
DrgnType *complex_type(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
DrgnType *struct_type(PyObject *self, PyObject *args, PyObject *kwds);
|
DrgnType *struct_type(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
DrgnType *union_type(PyObject *self, PyObject *args, PyObject *kwds);
|
DrgnType *union_type(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
|
DrgnType *class_type(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
DrgnType *enum_type(PyObject *self, PyObject *args, PyObject *kwds);
|
DrgnType *enum_type(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
DrgnType *typedef_type(PyObject *self, PyObject *args, PyObject *kwds);
|
DrgnType *typedef_type(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
DrgnType *pointer_type(PyObject *self, PyObject *args, PyObject *kwds);
|
DrgnType *pointer_type(PyObject *self, PyObject *args, PyObject *kwds);
|
||||||
|
@ -101,6 +101,8 @@ static PyMethodDef drgn_methods[] = {
|
|||||||
drgn_struct_type_DOC},
|
drgn_struct_type_DOC},
|
||||||
{"union_type", (PyCFunction)union_type, METH_VARARGS | METH_KEYWORDS,
|
{"union_type", (PyCFunction)union_type, METH_VARARGS | METH_KEYWORDS,
|
||||||
drgn_union_type_DOC},
|
drgn_union_type_DOC},
|
||||||
|
{"class_type", (PyCFunction)class_type, METH_VARARGS | METH_KEYWORDS,
|
||||||
|
drgn_class_type_DOC},
|
||||||
{"enum_type", (PyCFunction)enum_type, METH_VARARGS | METH_KEYWORDS,
|
{"enum_type", (PyCFunction)enum_type, METH_VARARGS | METH_KEYWORDS,
|
||||||
drgn_enum_type_DOC},
|
drgn_enum_type_DOC},
|
||||||
{"typedef_type", (PyCFunction)typedef_type,
|
{"typedef_type", (PyCFunction)typedef_type,
|
||||||
|
@ -303,6 +303,7 @@ static int serialize_py_object(struct drgn_program *prog, char *buf,
|
|||||||
return -1;
|
return -1;
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
return serialize_compound_value(prog, buf, buf_bit_size,
|
return serialize_compound_value(prog, buf, buf_bit_size,
|
||||||
bit_offset, value_obj,
|
bit_offset, value_obj,
|
||||||
type, little_endian);
|
type, little_endian);
|
||||||
@ -587,8 +588,7 @@ static PyObject *DrgnObject_compound_value(struct drgn_object *obj,
|
|||||||
if (!drgn_type_is_complete(underlying_type)) {
|
if (!drgn_type_is_complete(underlying_type)) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"cannot get value of incomplete %s",
|
"cannot get value of incomplete %s",
|
||||||
drgn_type_kind(underlying_type) ==
|
drgn_type_kind_spelling[drgn_type_kind(underlying_type)]);
|
||||||
DRGN_TYPE_STRUCT ? "struct" : "union");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,6 +742,7 @@ static PyObject *DrgnObject_value_impl(struct drgn_object *obj)
|
|||||||
return NULL;
|
return NULL;
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
return DrgnObject_compound_value(obj, underlying_type);
|
return DrgnObject_compound_value(obj, underlying_type);
|
||||||
case DRGN_TYPE_ARRAY:
|
case DRGN_TYPE_ARRAY:
|
||||||
return DrgnObject_array_value(obj, underlying_type);
|
return DrgnObject_array_value(obj, underlying_type);
|
||||||
@ -1424,8 +1425,8 @@ static PyObject *DrgnObject_getattro(DrgnObject *self, PyObject *attr_name)
|
|||||||
Py_CLEAR(res);
|
Py_CLEAR(res);
|
||||||
if (err->code == DRGN_ERROR_TYPE) {
|
if (err->code == DRGN_ERROR_TYPE) {
|
||||||
/*
|
/*
|
||||||
* If the object isn't a structure or union, raise the
|
* If the object doesn't have a compound type,
|
||||||
* original AttributeError.
|
* raise the original AttributeError.
|
||||||
*/
|
*/
|
||||||
PyErr_Restore(exc_type, exc_value, exc_traceback);
|
PyErr_Restore(exc_type, exc_value, exc_traceback);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1616,7 +1617,7 @@ static PyMethodDef DrgnObject_methods[] = {
|
|||||||
{"__floor__", (PyCFunction)DrgnObject_floor, METH_NOARGS},
|
{"__floor__", (PyCFunction)DrgnObject_floor, METH_NOARGS},
|
||||||
{"__ceil__", (PyCFunction)DrgnObject_ceil, METH_NOARGS},
|
{"__ceil__", (PyCFunction)DrgnObject_ceil, METH_NOARGS},
|
||||||
{"__dir__", (PyCFunction)DrgnObject_dir, METH_NOARGS,
|
{"__dir__", (PyCFunction)DrgnObject_dir, METH_NOARGS,
|
||||||
"dir() implementation which includes structure and union members."},
|
"dir() implementation which includes structure, union, and class members."},
|
||||||
{"__format__", (PyCFunction)DrgnObject_format, METH_O,
|
{"__format__", (PyCFunction)DrgnObject_format, METH_O,
|
||||||
"Object formatter."},
|
"Object formatter."},
|
||||||
{},
|
{},
|
||||||
|
@ -691,10 +691,9 @@ static int append_field(PyObject *parts, bool *first, const char *format, ...)
|
|||||||
_Py_IDENTIFIER(DrgnType_Repr);
|
_Py_IDENTIFIER(DrgnType_Repr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We only want to print compound types (structure and union types) one level
|
* We only want to print compound types one level deep in order to avoid very
|
||||||
* deep in order to avoid very deep recursion. Return 0 if this is the first
|
* deep recursion. Return 0 if this is the first level, 1 if this is a deeper
|
||||||
* level, 1 if this is a deeper level (and thus we shouldn't print more
|
* level (and thus we shouldn't print more members), and -1 on error.
|
||||||
* members), and -1 on error.
|
|
||||||
*/
|
*/
|
||||||
static int DrgnType_ReprEnter(DrgnType *self)
|
static int DrgnType_ReprEnter(DrgnType *self)
|
||||||
{
|
{
|
||||||
@ -1250,7 +1249,8 @@ out:
|
|||||||
|
|
||||||
static DrgnType *compound_type(PyObject *tag_obj, PyObject *size_obj,
|
static DrgnType *compound_type(PyObject *tag_obj, PyObject *size_obj,
|
||||||
PyObject *members_obj,
|
PyObject *members_obj,
|
||||||
enum drgn_qualifiers qualifiers, bool is_struct)
|
enum drgn_qualifiers qualifiers,
|
||||||
|
enum drgn_type_kind kind)
|
||||||
{
|
{
|
||||||
const char *tag;
|
const char *tag;
|
||||||
DrgnType *type_obj = NULL;
|
DrgnType *type_obj = NULL;
|
||||||
@ -1268,7 +1268,7 @@ static DrgnType *compound_type(PyObject *tag_obj, PyObject *size_obj,
|
|||||||
} else {
|
} else {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%s_type() tag must be str or None",
|
"%s_type() tag must be str or None",
|
||||||
is_struct ? "struct" : "union");
|
drgn_type_kind_spelling[kind]);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1276,7 +1276,7 @@ static DrgnType *compound_type(PyObject *tag_obj, PyObject *size_obj,
|
|||||||
if (size_obj != Py_None) {
|
if (size_obj != Py_None) {
|
||||||
PyErr_Format(PyExc_ValueError,
|
PyErr_Format(PyExc_ValueError,
|
||||||
"incomplete %s type must not have size",
|
"incomplete %s type must not have size",
|
||||||
is_struct ? "structure" : "union");
|
drgn_type_kind_spelling[kind]);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
type_obj = DrgnType_new(qualifiers, 0, 0);
|
type_obj = DrgnType_new(qualifiers, 0, 0);
|
||||||
@ -1290,7 +1290,7 @@ static DrgnType *compound_type(PyObject *tag_obj, PyObject *size_obj,
|
|||||||
|
|
||||||
if (size_obj == Py_None) {
|
if (size_obj == Py_None) {
|
||||||
PyErr_Format(PyExc_ValueError, "%s type must have size",
|
PyErr_Format(PyExc_ValueError, "%s type must have size",
|
||||||
is_struct ? "structure" : "union");
|
drgn_type_kind_spelling[kind]);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1335,17 +1335,35 @@ static DrgnType *compound_type(PyObject *tag_obj, PyObject *size_obj,
|
|||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
if (members_obj == Py_None) {
|
if (members_obj == Py_None) {
|
||||||
if (is_struct)
|
switch (kind) {
|
||||||
|
case DRGN_TYPE_STRUCT:
|
||||||
drgn_struct_type_init_incomplete(type_obj->type, tag);
|
drgn_struct_type_init_incomplete(type_obj->type, tag);
|
||||||
else
|
break;
|
||||||
|
case DRGN_TYPE_UNION:
|
||||||
drgn_union_type_init_incomplete(type_obj->type, tag);
|
drgn_union_type_init_incomplete(type_obj->type, tag);
|
||||||
|
break;
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
|
drgn_class_type_init_incomplete(type_obj->type, tag);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRGN_UNREACHABLE();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_struct) {
|
switch (kind) {
|
||||||
|
case DRGN_TYPE_STRUCT:
|
||||||
drgn_struct_type_init(type_obj->type, tag, size,
|
drgn_struct_type_init(type_obj->type, tag, size,
|
||||||
num_members);
|
num_members);
|
||||||
} else {
|
break;
|
||||||
|
case DRGN_TYPE_UNION:
|
||||||
drgn_union_type_init(type_obj->type, tag, size,
|
drgn_union_type_init(type_obj->type, tag, size,
|
||||||
num_members);
|
num_members);
|
||||||
|
break;
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
|
drgn_class_type_init(type_obj->type, tag, size,
|
||||||
|
num_members);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DRGN_UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return type_obj;
|
return type_obj;
|
||||||
@ -1371,7 +1389,8 @@ DrgnType *struct_type(PyObject *self, PyObject *args, PyObject *kwds)
|
|||||||
&qualifiers))
|
&qualifiers))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return compound_type(tag_obj, size_obj, members_obj, qualifiers, true);
|
return compound_type(tag_obj, size_obj, members_obj, qualifiers,
|
||||||
|
DRGN_TYPE_STRUCT);
|
||||||
}
|
}
|
||||||
|
|
||||||
DrgnType *union_type(PyObject *self, PyObject *args, PyObject *kwds)
|
DrgnType *union_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
@ -1388,7 +1407,26 @@ DrgnType *union_type(PyObject *self, PyObject *args, PyObject *kwds)
|
|||||||
&qualifiers))
|
&qualifiers))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return compound_type(tag_obj, size_obj, members_obj, qualifiers, false);
|
return compound_type(tag_obj, size_obj, members_obj, qualifiers,
|
||||||
|
DRGN_TYPE_UNION);
|
||||||
|
}
|
||||||
|
|
||||||
|
DrgnType *class_type(PyObject *self, PyObject *args, PyObject *kwds)
|
||||||
|
{
|
||||||
|
static char *keywords[] = { "tag", "size", "members", "qualifiers", NULL, };
|
||||||
|
PyObject *tag_obj;
|
||||||
|
PyObject *size_obj = Py_None;
|
||||||
|
PyObject *members_obj = Py_None;
|
||||||
|
unsigned char qualifiers = 0;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOO&:class_type",
|
||||||
|
keywords, &tag_obj, &size_obj,
|
||||||
|
&members_obj, qualifiers_converter,
|
||||||
|
&qualifiers))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return compound_type(tag_obj, size_obj, members_obj, qualifiers,
|
||||||
|
DRGN_TYPE_CLASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unpack_enumerator(DrgnType *type_obj, PyObject *enumerators_seq,
|
static int unpack_enumerator(DrgnType *type_obj, PyObject *enumerators_seq,
|
||||||
|
@ -14,6 +14,7 @@ const char * const drgn_type_kind_spelling[] = {
|
|||||||
[DRGN_TYPE_COMPLEX] = "complex",
|
[DRGN_TYPE_COMPLEX] = "complex",
|
||||||
[DRGN_TYPE_STRUCT] = "struct",
|
[DRGN_TYPE_STRUCT] = "struct",
|
||||||
[DRGN_TYPE_UNION] = "union",
|
[DRGN_TYPE_UNION] = "union",
|
||||||
|
[DRGN_TYPE_CLASS] = "class",
|
||||||
[DRGN_TYPE_ENUM] = "enum",
|
[DRGN_TYPE_ENUM] = "enum",
|
||||||
[DRGN_TYPE_TYPEDEF] = "typedef",
|
[DRGN_TYPE_TYPEDEF] = "typedef",
|
||||||
[DRGN_TYPE_POINTER] = "pointer",
|
[DRGN_TYPE_POINTER] = "pointer",
|
||||||
@ -297,6 +298,27 @@ void drgn_union_type_init_incomplete(struct drgn_type *type, const char *tag)
|
|||||||
type->_private.num_members = 0;
|
type->_private.num_members = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drgn_class_type_init(struct drgn_type *type, const char *tag,
|
||||||
|
uint64_t size, size_t num_members)
|
||||||
|
{
|
||||||
|
type->_private.kind = DRGN_TYPE_CLASS;
|
||||||
|
type->_private.is_complete = true;
|
||||||
|
type->_private.primitive = DRGN_NOT_PRIMITIVE_TYPE;
|
||||||
|
type->_private.tag = tag;
|
||||||
|
type->_private.size = size;
|
||||||
|
type->_private.num_members = num_members;
|
||||||
|
}
|
||||||
|
|
||||||
|
void drgn_class_type_init_incomplete(struct drgn_type *type, const char *tag)
|
||||||
|
{
|
||||||
|
type->_private.kind = DRGN_TYPE_CLASS;
|
||||||
|
type->_private.is_complete = false;
|
||||||
|
type->_private.primitive = DRGN_NOT_PRIMITIVE_TYPE;
|
||||||
|
type->_private.tag = tag;
|
||||||
|
type->_private.size = 0;
|
||||||
|
type->_private.num_members = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void drgn_enum_type_init(struct drgn_type *type, const char *tag,
|
void drgn_enum_type_init(struct drgn_type *type, const char *tag,
|
||||||
struct drgn_type *compatible_type,
|
struct drgn_type *compatible_type,
|
||||||
size_t num_enumerators)
|
size_t num_enumerators)
|
||||||
@ -717,8 +739,14 @@ LIBDRGN_PUBLIC struct drgn_error *drgn_type_sizeof(struct drgn_type *type,
|
|||||||
uint64_t *ret)
|
uint64_t *ret)
|
||||||
{
|
{
|
||||||
struct drgn_error *err;
|
struct drgn_error *err;
|
||||||
|
enum drgn_type_kind kind = drgn_type_kind(type);
|
||||||
|
|
||||||
switch (drgn_type_kind(type)) {
|
if (!drgn_type_is_complete(type)) {
|
||||||
|
return drgn_error_format(DRGN_ERROR_TYPE,
|
||||||
|
"cannot get size of incomplete %s type",
|
||||||
|
drgn_type_kind_spelling[kind]);
|
||||||
|
}
|
||||||
|
switch (kind) {
|
||||||
case DRGN_TYPE_INT:
|
case DRGN_TYPE_INT:
|
||||||
case DRGN_TYPE_BOOL:
|
case DRGN_TYPE_BOOL:
|
||||||
case DRGN_TYPE_FLOAT:
|
case DRGN_TYPE_FLOAT:
|
||||||
@ -727,33 +755,14 @@ LIBDRGN_PUBLIC struct drgn_error *drgn_type_sizeof(struct drgn_type *type,
|
|||||||
*ret = drgn_type_size(type);
|
*ret = drgn_type_size(type);
|
||||||
return NULL;
|
return NULL;
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
if (!drgn_type_is_complete(type)) {
|
|
||||||
return drgn_error_create(DRGN_ERROR_TYPE,
|
|
||||||
"cannot get size of incomplete structure type");
|
|
||||||
}
|
|
||||||
*ret = drgn_type_size(type);
|
|
||||||
return NULL;
|
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
if (!drgn_type_is_complete(type)) {
|
case DRGN_TYPE_CLASS:
|
||||||
return drgn_error_create(DRGN_ERROR_TYPE,
|
|
||||||
"cannot get size of incomplete union type");
|
|
||||||
}
|
|
||||||
*ret = drgn_type_size(type);
|
*ret = drgn_type_size(type);
|
||||||
return NULL;
|
return NULL;
|
||||||
case DRGN_TYPE_ENUM:
|
case DRGN_TYPE_ENUM:
|
||||||
if (!drgn_type_is_complete(type)) {
|
|
||||||
return drgn_error_create(DRGN_ERROR_TYPE,
|
|
||||||
"cannot get size of incomplete enumerated type");
|
|
||||||
}
|
|
||||||
/* fallthrough */
|
|
||||||
case DRGN_TYPE_TYPEDEF:
|
case DRGN_TYPE_TYPEDEF:
|
||||||
return drgn_type_sizeof(drgn_type_type(type).type, ret);
|
return drgn_type_sizeof(drgn_type_type(type).type, ret);
|
||||||
case DRGN_TYPE_ARRAY:
|
case DRGN_TYPE_ARRAY:
|
||||||
if (!drgn_type_is_complete(type)) {
|
|
||||||
return drgn_error_create(DRGN_ERROR_TYPE,
|
|
||||||
"cannot get size of incomplete array type");
|
|
||||||
}
|
|
||||||
|
|
||||||
err = drgn_type_sizeof(drgn_type_type(type).type, ret);
|
err = drgn_type_sizeof(drgn_type_type(type).type, ret);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@ -801,6 +810,7 @@ enum drgn_object_kind drgn_type_object_kind(struct drgn_type *type)
|
|||||||
return DRGN_OBJECT_BUFFER;
|
return DRGN_OBJECT_BUFFER;
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
case DRGN_TYPE_ARRAY:
|
case DRGN_TYPE_ARRAY:
|
||||||
return (drgn_type_is_complete(type) ? DRGN_OBJECT_BUFFER :
|
return (drgn_type_is_complete(type) ? DRGN_OBJECT_BUFFER :
|
||||||
DRGN_OBJECT_INCOMPLETE_BUFFER);
|
DRGN_OBJECT_INCOMPLETE_BUFFER);
|
||||||
@ -849,6 +859,9 @@ struct drgn_error *drgn_error_incomplete_type(const char *format,
|
|||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
return drgn_error_format(DRGN_ERROR_TYPE, format,
|
return drgn_error_format(DRGN_ERROR_TYPE, format,
|
||||||
"incomplete union");
|
"incomplete union");
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
|
return drgn_error_format(DRGN_ERROR_TYPE, format,
|
||||||
|
"incomplete class");
|
||||||
case DRGN_TYPE_ENUM:
|
case DRGN_TYPE_ENUM:
|
||||||
return drgn_error_format(DRGN_ERROR_TYPE, format,
|
return drgn_error_format(DRGN_ERROR_TYPE, format,
|
||||||
"incomplete enumerated");
|
"incomplete enumerated");
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
* Lazily-evaluated types.
|
* Lazily-evaluated types.
|
||||||
*
|
*
|
||||||
* The graph of types in a program can be very deep (and often cyclical), so
|
* The graph of types in a program can be very deep (and often cyclical), so
|
||||||
* drgn lazily evaluates the types of structure/union members and function
|
* drgn lazily evaluates the types of compound type members and function
|
||||||
* parameters.
|
* parameters.
|
||||||
*
|
*
|
||||||
* @{
|
* @{
|
||||||
@ -297,6 +297,30 @@ void drgn_union_type_init(struct drgn_type *type, const char *tag,
|
|||||||
*/
|
*/
|
||||||
void drgn_union_type_init_incomplete(struct drgn_type *type, const char *tag);
|
void drgn_union_type_init_incomplete(struct drgn_type *type, const char *tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a class type.
|
||||||
|
* @param[out] type Type to initialize. This must have @c num_members @ref
|
||||||
|
* drgn_type_memer%s allocated after it. Similar to struct type, the members
|
||||||
|
* must be initialized with @ref drgn_type_member_init() (either before or after
|
||||||
|
* this function is called).
|
||||||
|
* @param[in] tag Name of the type.
|
||||||
|
* @param[in] size Size of the type in bytes.
|
||||||
|
* @param[in] num_members The number of members in the type.
|
||||||
|
*/
|
||||||
|
void drgn_class_type_init(struct drgn_type *type, const char *tag,
|
||||||
|
uint64_t size, size_t num_members);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize an incomplete class type.
|
||||||
|
*
|
||||||
|
* @c size and @c num_members are set to zero and @c is_complete is set to @c
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* @param[out] type Type to initialize.
|
||||||
|
* @param[int] tag Name of the type.
|
||||||
|
*/
|
||||||
|
void drgn_class_type_init_incomplete(struct drgn_type *type, const char *tag);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize a signed enumerator of a type.
|
* Initialize a signed enumerator of a type.
|
||||||
*
|
*
|
||||||
@ -518,14 +542,15 @@ static inline bool drgn_enum_type_is_signed(struct drgn_type *type)
|
|||||||
/**
|
/**
|
||||||
* Get whether a type is anonymous (i.e., the type has no name).
|
* Get whether a type is anonymous (i.e., the type has no name).
|
||||||
*
|
*
|
||||||
* This may be @c false for structure, union, and enum types. Otherwise, it is
|
* This may be @c false for structure, union, class, and enum types. Otherwise,
|
||||||
* always true.
|
* it is always true.
|
||||||
*/
|
*/
|
||||||
static inline bool drgn_type_is_anonymous(struct drgn_type *type)
|
static inline bool drgn_type_is_anonymous(struct drgn_type *type)
|
||||||
{
|
{
|
||||||
switch (drgn_type_kind(type)) {
|
switch (drgn_type_kind(type)) {
|
||||||
case DRGN_TYPE_STRUCT:
|
case DRGN_TYPE_STRUCT:
|
||||||
case DRGN_TYPE_UNION:
|
case DRGN_TYPE_UNION:
|
||||||
|
case DRGN_TYPE_CLASS:
|
||||||
case DRGN_TYPE_ENUM:
|
case DRGN_TYPE_ENUM:
|
||||||
return !drgn_type_tag(type);
|
return !drgn_type_tag(type);
|
||||||
default:
|
default:
|
||||||
|
@ -574,14 +574,15 @@ struct drgn_error *drgn_type_index_find_member(struct drgn_type_index *tindex,
|
|||||||
/*
|
/*
|
||||||
* Cache miss. One of the following is true:
|
* Cache miss. One of the following is true:
|
||||||
*
|
*
|
||||||
* 1. The type isn't a structure or union, which is a type error.
|
* 1. The type isn't a structure, union, or class, which is a type
|
||||||
|
* error.
|
||||||
* 2. The type hasn't been cached, which means we need to cache it and
|
* 2. The type hasn't been cached, which means we need to cache it and
|
||||||
* check again.
|
* check again.
|
||||||
* 3. The type has already been cached, which means the member doesn't
|
* 3. The type has already been cached, which means the member doesn't
|
||||||
* exist.
|
* exist.
|
||||||
*/
|
*/
|
||||||
if (!drgn_type_has_members(key.type)) {
|
if (!drgn_type_has_members(key.type)) {
|
||||||
return drgn_type_error("'%s' is not a structure or union",
|
return drgn_type_error("'%s' is not a structure, union, or class",
|
||||||
type);
|
type);
|
||||||
}
|
}
|
||||||
cached_hp = drgn_type_set_hash(&key.type);
|
cached_hp = drgn_type_set_hash(&key.type);
|
||||||
|
@ -178,7 +178,8 @@ drgn_type_index_find_primitive(struct drgn_type_index *tindex,
|
|||||||
* drgn_language::find_type().
|
* drgn_language::find_type().
|
||||||
*
|
*
|
||||||
* @param[in] kind Kind of type to find. Must be @ref DRGN_TYPE_STRUCT, @ref
|
* @param[in] kind Kind of type to find. Must be @ref DRGN_TYPE_STRUCT, @ref
|
||||||
* DRGN_TYPE_UNION, @ref DRGN_TYPE_ENUM, or @ref DRGN_TYPE_TYPEDEF.
|
* DRGN_TYPE_UNION, @ref DRGN_TYPE_CLASS, @ref DRGN_TYPE_ENUM, or @ref
|
||||||
|
* DRGN_TYPE_TYPEDEF.
|
||||||
* @param[in] name Name of the type.
|
* @param[in] name Name of the type.
|
||||||
* @param[in] name_len Length of @p name in bytes.
|
* @param[in] name_len Length of @p name in bytes.
|
||||||
* @param[in] filename See @ref drgn_type_index_find().
|
* @param[in] filename See @ref drgn_type_index_find().
|
||||||
|
@ -11,6 +11,7 @@ from drgn import (
|
|||||||
Program,
|
Program,
|
||||||
Type,
|
Type,
|
||||||
TypeKind,
|
TypeKind,
|
||||||
|
class_type,
|
||||||
enum_type,
|
enum_type,
|
||||||
float_type,
|
float_type,
|
||||||
int_type,
|
int_type,
|
||||||
@ -20,6 +21,11 @@ from drgn import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
coord_type = class_type('coord', 12, (
|
||||||
|
(int_type('int', 4, True), 'x', 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
(int_type('int', 4, True), 'z', 64),
|
||||||
|
))
|
||||||
point_type = struct_type('point', 8, (
|
point_type = struct_type('point', 8, (
|
||||||
(int_type('int', 4, True), 'x', 0),
|
(int_type('int', 4, True), 'x', 0),
|
||||||
(int_type('int', 4, True), 'y', 32),
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
@ -8,6 +8,7 @@ from drgn import (
|
|||||||
Program,
|
Program,
|
||||||
Qualifiers,
|
Qualifiers,
|
||||||
array_type,
|
array_type,
|
||||||
|
class_type,
|
||||||
complex_type,
|
complex_type,
|
||||||
enum_type,
|
enum_type,
|
||||||
float_type,
|
float_type,
|
||||||
@ -19,7 +20,14 @@ from drgn import (
|
|||||||
union_type,
|
union_type,
|
||||||
void_type,
|
void_type,
|
||||||
)
|
)
|
||||||
from tests import ObjectTestCase, color_type, option_type, pid_type, point_type
|
from tests import (
|
||||||
|
ObjectTestCase,
|
||||||
|
color_type,
|
||||||
|
coord_type,
|
||||||
|
option_type,
|
||||||
|
pid_type,
|
||||||
|
point_type,
|
||||||
|
)
|
||||||
from tests.dwarf import DW_AT, DW_ATE, DW_FORM, DW_TAG
|
from tests.dwarf import DW_AT, DW_ATE, DW_FORM, DW_TAG
|
||||||
from tests.dwarfwriter import compile_dwarf, DwarfDie, DwarfAttrib
|
from tests.dwarfwriter import compile_dwarf, DwarfDie, DwarfAttrib
|
||||||
|
|
||||||
@ -709,6 +717,109 @@ class TestTypes(unittest.TestCase):
|
|||||||
self.type_from_dwarf, dies)
|
self.type_from_dwarf, dies)
|
||||||
dies[0].attribs.insert(1, size)
|
dies[0].attribs.insert(1, size)
|
||||||
|
|
||||||
|
def test_class(self):
|
||||||
|
dies = [
|
||||||
|
DwarfDie(
|
||||||
|
DW_TAG.class_type,
|
||||||
|
[
|
||||||
|
DwarfAttrib(DW_AT.name, DW_FORM.string, 'coord'),
|
||||||
|
DwarfAttrib(DW_AT.byte_size, DW_FORM.data1, 12),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
DwarfDie(
|
||||||
|
DW_TAG.member,
|
||||||
|
[
|
||||||
|
DwarfAttrib(DW_AT.name, DW_FORM.string, 'x'),
|
||||||
|
DwarfAttrib(DW_AT.data_member_location, DW_FORM.data1, 0),
|
||||||
|
DwarfAttrib(DW_AT.type, DW_FORM.ref4, 1),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
DwarfDie(
|
||||||
|
DW_TAG.member,
|
||||||
|
[
|
||||||
|
DwarfAttrib(DW_AT.name, DW_FORM.string, 'y'),
|
||||||
|
DwarfAttrib(DW_AT.data_member_location, DW_FORM.data1, 4),
|
||||||
|
DwarfAttrib(DW_AT.type, DW_FORM.ref4, 1),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
DwarfDie(
|
||||||
|
DW_TAG.member,
|
||||||
|
[
|
||||||
|
DwarfAttrib(DW_AT.name, DW_FORM.string, 'z'),
|
||||||
|
DwarfAttrib(DW_AT.data_member_location, DW_FORM.data1, 8),
|
||||||
|
DwarfAttrib(DW_AT.type, DW_FORM.ref4, 1),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
int_die,
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertFromDwarf(dies, coord_type)
|
||||||
|
|
||||||
|
tag = dies[0].attribs.pop(0)
|
||||||
|
self.assertFromDwarf(
|
||||||
|
dies, class_type(None, coord_type.size, coord_type.members))
|
||||||
|
dies[0].attribs.insert(0, tag)
|
||||||
|
|
||||||
|
children = list(dies[0].children)
|
||||||
|
dies[0].children.clear()
|
||||||
|
self.assertFromDwarf(
|
||||||
|
dies, class_type('coord', coord_type.size, ()))
|
||||||
|
size = dies[0].attribs.pop(1)
|
||||||
|
dies[0].attribs.append(DwarfAttrib(DW_AT.declaration, DW_FORM.flag_present, True))
|
||||||
|
self.assertFromDwarf(dies, class_type('coord'))
|
||||||
|
del dies[0].attribs[-1]
|
||||||
|
dies[0].attribs.insert(1, size)
|
||||||
|
dies[0].children.extend(children)
|
||||||
|
|
||||||
|
name = dies[0].children[0].attribs.pop(0)
|
||||||
|
self.assertFromDwarf(
|
||||||
|
dies,
|
||||||
|
class_type('coord', coord_type.size, (
|
||||||
|
(int_type('int', 4, True), None, 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
(int_type('int', 4, True), 'z', 64),
|
||||||
|
)))
|
||||||
|
dies[0].children[0].attribs.insert(0, name)
|
||||||
|
|
||||||
|
tag = dies[0].attribs.pop(0)
|
||||||
|
dies[0].attribs.insert(0, DwarfAttrib(DW_AT.name, DW_FORM.data1, 0))
|
||||||
|
self.assertRaisesRegex(Exception,
|
||||||
|
'DW_TAG_class_type has invalid DW_AT_name',
|
||||||
|
self.type_from_dwarf, dies)
|
||||||
|
dies[0].attribs[0] = tag
|
||||||
|
|
||||||
|
size = dies[0].attribs.pop(1)
|
||||||
|
self.assertRaisesRegex(Exception,
|
||||||
|
'DW_TAG_class_type has missing or invalid DW_AT_byte_size',
|
||||||
|
self.type_from_dwarf, dies)
|
||||||
|
dies[0].attribs.insert(1, size)
|
||||||
|
|
||||||
|
name = dies[0].children[0].attribs.pop(0)
|
||||||
|
dies[0].children[0].attribs.insert(0, DwarfAttrib(DW_AT.name, DW_FORM.data1, 0))
|
||||||
|
self.assertRaisesRegex(Exception,
|
||||||
|
'DW_TAG_member has invalid DW_AT_name',
|
||||||
|
self.type_from_dwarf, dies)
|
||||||
|
dies[0].children[0].attribs[0] = name
|
||||||
|
|
||||||
|
location = dies[0].children[0].attribs[1]
|
||||||
|
dies[0].children[0].attribs[1] = DwarfAttrib(DW_AT.data_member_location, DW_FORM.string, 'foo')
|
||||||
|
self.assertRaisesRegex(Exception,
|
||||||
|
'DW_TAG_member has invalid DW_AT_data_member_location',
|
||||||
|
self.type_from_dwarf, dies)
|
||||||
|
dies[0].children[0].attribs[1] = location
|
||||||
|
|
||||||
|
type_ = dies[0].children[0].attribs.pop(2)
|
||||||
|
self.assertRaisesRegex(Exception,
|
||||||
|
'DW_TAG_member is missing DW_AT_type',
|
||||||
|
self.type_from_dwarf, dies)
|
||||||
|
dies[0].children[0].attribs.insert(2, DwarfAttrib(DW_AT.type, DW_FORM.string, 'foo'))
|
||||||
|
self.assertRaisesRegex(Exception,
|
||||||
|
'DW_TAG_member has invalid DW_AT_type',
|
||||||
|
self.type_from_dwarf, dies)
|
||||||
|
dies[0].children[0].attribs[2] = type_
|
||||||
|
|
||||||
def test_lazy_cycle(self):
|
def test_lazy_cycle(self):
|
||||||
dies = [
|
dies = [
|
||||||
DwarfDie(
|
DwarfDie(
|
||||||
|
@ -3,21 +3,22 @@ import operator
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from drgn import (
|
from drgn import (
|
||||||
|
Qualifiers,
|
||||||
array_type,
|
array_type,
|
||||||
bool_type,
|
bool_type,
|
||||||
|
class_type,
|
||||||
complex_type,
|
complex_type,
|
||||||
enum_type,
|
enum_type,
|
||||||
float_type,
|
float_type,
|
||||||
function_type,
|
function_type,
|
||||||
int_type,
|
int_type,
|
||||||
pointer_type,
|
pointer_type,
|
||||||
Qualifiers,
|
|
||||||
struct_type,
|
struct_type,
|
||||||
typedef_type,
|
typedef_type,
|
||||||
union_type,
|
union_type,
|
||||||
void_type,
|
void_type,
|
||||||
)
|
)
|
||||||
from tests import point_type
|
from tests import coord_type, point_type
|
||||||
from tests.libdrgn import C_TOKEN, drgn_lexer_c, Lexer
|
from tests.libdrgn import C_TOKEN, drgn_lexer_c, Lexer
|
||||||
|
|
||||||
|
|
||||||
@ -78,6 +79,12 @@ class TestPrettyPrintTypeName(unittest.TestCase):
|
|||||||
self.assertQualifiedTypeName('union <anonymous>', False, union_type,
|
self.assertQualifiedTypeName('union <anonymous>', False, union_type,
|
||||||
None)
|
None)
|
||||||
|
|
||||||
|
def test_class(self):
|
||||||
|
self.assertQualifiedTypeName('class coord', True, class_type,
|
||||||
|
'coord')
|
||||||
|
self.assertQualifiedTypeName('class <anonymous>', False, class_type,
|
||||||
|
None)
|
||||||
|
|
||||||
def test_enum(self):
|
def test_enum(self):
|
||||||
self.assertQualifiedTypeName('enum color', True, enum_type, 'color',
|
self.assertQualifiedTypeName('enum color', True, enum_type, 'color',
|
||||||
None, None),
|
None, None),
|
||||||
@ -279,6 +286,14 @@ const union foo {
|
|||||||
unsigned char a[4];
|
unsigned char a[4];
|
||||||
}""")
|
}""")
|
||||||
|
|
||||||
|
def test_class(self):
|
||||||
|
self.assertPrettyPrint(coord_type, """\
|
||||||
|
class coord {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int z;
|
||||||
|
}""")
|
||||||
|
|
||||||
def test_enum(self):
|
def test_enum(self):
|
||||||
t = enum_type('color', int_type('unsigned int', 4, False), (
|
t = enum_type('color', int_type('unsigned int', 4, False), (
|
||||||
('RED', 0),
|
('RED', 0),
|
||||||
|
@ -26,6 +26,7 @@ from tests import (
|
|||||||
MockMemorySegment,
|
MockMemorySegment,
|
||||||
ObjectTestCase,
|
ObjectTestCase,
|
||||||
color_type,
|
color_type,
|
||||||
|
coord_type,
|
||||||
line_segment_type,
|
line_segment_type,
|
||||||
mock_program,
|
mock_program,
|
||||||
option_type,
|
option_type,
|
||||||
@ -1200,7 +1201,7 @@ class TestCOperators(ObjectTestCase):
|
|||||||
r'container_of\(\) argument must be a pointer',
|
r'container_of\(\) argument must be a pointer',
|
||||||
container_of, obj[0], point_type, 'x')
|
container_of, obj[0], point_type, 'x')
|
||||||
|
|
||||||
self.assertRaisesRegex(TypeError, 'not a structure or union',
|
self.assertRaisesRegex(TypeError, 'not a structure, union, or class',
|
||||||
container_of, obj, obj.type_, 'x'),
|
container_of, obj, obj.type_, 'x'),
|
||||||
|
|
||||||
type_ = struct_type('foo', 16, (
|
type_ = struct_type('foo', 16, (
|
||||||
@ -1771,7 +1772,7 @@ class TestGenericOperators(ObjectTestCase):
|
|||||||
self.assertEqual(obj.y, Object(self.prog, 'int', value=1))
|
self.assertEqual(obj.y, Object(self.prog, 'int', value=1))
|
||||||
|
|
||||||
obj = Object(self.prog, 'int', value=1)
|
obj = Object(self.prog, 'int', value=1)
|
||||||
self.assertRaisesRegex(TypeError, "'int' is not a structure or union",
|
self.assertRaisesRegex(TypeError, "'int' is not a structure, union, or class",
|
||||||
obj.member_, 'x')
|
obj.member_, 'x')
|
||||||
self.assertRaisesRegex(AttributeError, 'no attribute', getattr, obj,
|
self.assertRaisesRegex(AttributeError, 'no attribute', getattr, obj,
|
||||||
'x')
|
'x')
|
||||||
|
@ -6,6 +6,7 @@ from drgn import (
|
|||||||
TypeKind,
|
TypeKind,
|
||||||
array_type,
|
array_type,
|
||||||
bool_type,
|
bool_type,
|
||||||
|
class_type,
|
||||||
complex_type,
|
complex_type,
|
||||||
enum_type,
|
enum_type,
|
||||||
float_type,
|
float_type,
|
||||||
@ -366,6 +367,144 @@ class TestType(unittest.TestCase):
|
|||||||
(int_type('unsigned int', 4, False), 'y', 0, 4),
|
(int_type('unsigned int', 4, False), 'y', 0, 4),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
def test_class(self):
|
||||||
|
t = class_type('coord', 12, (
|
||||||
|
(int_type('int', 4, True), 'x', 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
(int_type('int', 4, True), 'z', 64),
|
||||||
|
))
|
||||||
|
self.assertEqual(t.kind, TypeKind.CLASS)
|
||||||
|
self.assertIsNone(t.primitive)
|
||||||
|
self.assertEqual(t.tag, 'coord')
|
||||||
|
self.assertEqual(t.size, 12)
|
||||||
|
self.assertEqual(t.members, (
|
||||||
|
(int_type('int', 4, True), 'x', 0, 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32, 0),
|
||||||
|
(int_type('int', 4, True), 'z', 64, 0),
|
||||||
|
))
|
||||||
|
self.assertTrue(t.is_complete())
|
||||||
|
|
||||||
|
self.assertEqual(t, class_type('coord', 12, (
|
||||||
|
(int_type('int', 4, True), 'x', 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
(int_type('int', 4, True), 'z', 64),
|
||||||
|
)))
|
||||||
|
# Different tag.
|
||||||
|
self.assertNotEqual(t, class_type('crd', 12, (
|
||||||
|
(int_type('int', 4, True), 'x', 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
(int_type('int', 4, True), 'z', 64),
|
||||||
|
)))
|
||||||
|
# Different size.
|
||||||
|
self.assertNotEqual(t, class_type('coord', 16, (
|
||||||
|
(int_type('int', 4, True), 'x', 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
(int_type('int', 4, True), 'z', 64),
|
||||||
|
)))
|
||||||
|
# One is anonymous.
|
||||||
|
self.assertNotEqual(t, class_type(None, 12, (
|
||||||
|
(int_type('int', 4, True), 'x', 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
(int_type('int', 4, True), 'z', 64),
|
||||||
|
)))
|
||||||
|
# Different members.
|
||||||
|
self.assertNotEqual(t, class_type('coord', 12, (
|
||||||
|
(int_type('long', 8, True), 'x', 0),
|
||||||
|
(int_type('long', 8, True), 'y', 64),
|
||||||
|
(int_type('long', 8, True), 'z', 128),
|
||||||
|
)))
|
||||||
|
# Different number of members.
|
||||||
|
self.assertNotEqual(t, class_type('coord', 12, (
|
||||||
|
(int_type('int', 4, True), 'x', 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
)))
|
||||||
|
# One member is anonymous.
|
||||||
|
self.assertNotEqual(t, class_type('coord', 8, (
|
||||||
|
(int_type('int', 4, True), 'x', 0, 0),
|
||||||
|
(int_type('int', 4, True), None, 32, 0),
|
||||||
|
(int_type('int', 4, True), 'z', 64, 0),
|
||||||
|
)))
|
||||||
|
# One is incomplete.
|
||||||
|
self.assertNotEqual(t, class_type('coord'))
|
||||||
|
|
||||||
|
self.assertEqual(repr(t), "class_type(tag='coord', size=12, members=((int_type(name='int', size=4, is_signed=True), 'x', 0, 0), (int_type(name='int', size=4, is_signed=True), 'y', 32, 0), (int_type(name='int', size=4, is_signed=True), 'z', 64, 0)))")
|
||||||
|
self.assertEqual(sizeof(t), 12)
|
||||||
|
|
||||||
|
t = class_type(None, 12, (
|
||||||
|
(int_type('int', 4, True), 'x', 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32),
|
||||||
|
(int_type('int', 4, True), 'z', 64),
|
||||||
|
))
|
||||||
|
self.assertEqual(t.kind, TypeKind.CLASS)
|
||||||
|
self.assertIsNone(t.primitive)
|
||||||
|
self.assertIsNone(t.tag)
|
||||||
|
self.assertEqual(t.size, 12)
|
||||||
|
self.assertEqual(t.members, (
|
||||||
|
(int_type('int', 4, True), 'x', 0, 0),
|
||||||
|
(int_type('int', 4, True), 'y', 32, 0),
|
||||||
|
(int_type('int', 4, True), 'z', 64, 0),
|
||||||
|
))
|
||||||
|
self.assertTrue(t.is_complete())
|
||||||
|
|
||||||
|
t = class_type('color', 0, ())
|
||||||
|
self.assertEqual(t.kind, TypeKind.CLASS)
|
||||||
|
self.assertIsNone(t.primitive)
|
||||||
|
self.assertEqual(t.tag, 'color')
|
||||||
|
self.assertEqual(t.size, 0)
|
||||||
|
self.assertEqual(t.members, ())
|
||||||
|
self.assertTrue(t.is_complete())
|
||||||
|
self.assertEqual(repr(t), "class_type(tag='color', size=0, members=())")
|
||||||
|
|
||||||
|
t = class_type('color')
|
||||||
|
self.assertEqual(t.kind, TypeKind.CLASS)
|
||||||
|
self.assertIsNone(t.primitive)
|
||||||
|
self.assertEqual(t.tag, 'color')
|
||||||
|
self.assertIsNone(t.size)
|
||||||
|
self.assertIsNone(t.members)
|
||||||
|
self.assertFalse(t.is_complete())
|
||||||
|
self.assertEqual(repr(t), "class_type(tag='color', size=None, members=None)")
|
||||||
|
|
||||||
|
t = class_type(None, None, None)
|
||||||
|
self.assertEqual(t.kind, TypeKind.CLASS)
|
||||||
|
self.assertIsNone(t.primitive)
|
||||||
|
self.assertEqual(t.tag, None)
|
||||||
|
self.assertIsNone(t.size)
|
||||||
|
self.assertIsNone(t.members)
|
||||||
|
self.assertFalse(t.is_complete())
|
||||||
|
self.assertEqual(repr(t), "class_type(tag=None, size=None, members=None)")
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, class_type, 4)
|
||||||
|
self.assertRaisesRegex(ValueError, 'must not have size', class_type,
|
||||||
|
'coord', 12, None)
|
||||||
|
self.assertRaisesRegex(ValueError, 'must have size', class_type,
|
||||||
|
'coord', None, ())
|
||||||
|
self.assertRaisesRegex(TypeError, 'must be sequence or None',
|
||||||
|
class_type, 'coord', 12, 4)
|
||||||
|
self.assertRaisesRegex(TypeError, 'must be.*sequence', class_type,
|
||||||
|
'coord', 12, (4))
|
||||||
|
self.assertRaisesRegex(ValueError, 'must be.*sequence', class_type,
|
||||||
|
'coord', 12, ((),))
|
||||||
|
self.assertRaisesRegex(TypeError, 'must be string or None',
|
||||||
|
class_type, 'coord', 12,
|
||||||
|
((int_type('int', 4, True), 4, 0),))
|
||||||
|
self.assertRaisesRegex(TypeError, 'must be integer', class_type,
|
||||||
|
'coord', 12,
|
||||||
|
((int_type('int', 4, True), 'x', None),))
|
||||||
|
self.assertRaisesRegex(TypeError, 'must be Type', class_type, 'coord',
|
||||||
|
12, ((None, 'x', 0),))
|
||||||
|
|
||||||
|
# Bit size.
|
||||||
|
t = class_type('coord', 12, (
|
||||||
|
(int_type('int', 4, True), 'x', 0, 4),
|
||||||
|
(int_type('int', 4, True), 'y', 32, 4),
|
||||||
|
(int_type('int', 4, True), 'z', 64, 4),
|
||||||
|
))
|
||||||
|
self.assertEqual(t.members, (
|
||||||
|
(int_type('int', 4, True), 'x', 0, 4),
|
||||||
|
(int_type('int', 4, True), 'y', 32, 4),
|
||||||
|
(int_type('int', 4, True), 'z', 64, 4),
|
||||||
|
))
|
||||||
|
|
||||||
def test_enum(self):
|
def test_enum(self):
|
||||||
t = enum_type('color', int_type('unsigned int', 4, False),
|
t = enum_type('color', int_type('unsigned int', 4, False),
|
||||||
(('RED', 0), ('GREEN', 1), ('BLUE', 2)))
|
(('RED', 0), ('GREEN', 1), ('BLUE', 2)))
|
||||||
|
Loading…
Reference in New Issue
Block a user