2021-11-21 23:59:44 +00:00
|
|
|
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
2022-11-02 00:05:16 +00:00
|
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
from functools import reduce
|
2022-11-30 21:52:25 +00:00
|
|
|
from itertools import chain
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
import operator
|
|
|
|
|
2021-02-22 00:11:19 +00:00
|
|
|
from drgn import (
|
|
|
|
Object,
|
|
|
|
Qualifiers,
|
|
|
|
Type,
|
|
|
|
TypeEnumerator,
|
|
|
|
TypeMember,
|
|
|
|
TypeParameter,
|
|
|
|
cast,
|
|
|
|
container_of,
|
|
|
|
)
|
2022-01-07 22:28:01 +00:00
|
|
|
from tests import MockProgramTestCase, TestCase
|
2022-02-18 06:18:53 +00:00
|
|
|
from tests.libdrgn import C_TOKEN, Lexer, drgn_c_family_lexer_func
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
|
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
class TestPrettyPrintTypeName(MockProgramTestCase):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
def assertTypeName(self, type, expected, same_as_definition=False):
|
|
|
|
self.assertEqual(type.type_name(), expected)
|
|
|
|
if same_as_definition:
|
|
|
|
self.assertEqual(str(type), expected)
|
|
|
|
|
|
|
|
def assertQualifiedTypeName(self, expected, same_as_definition, constructor, *args):
|
|
|
|
self.assertEqual(constructor(*args).type_name(), expected)
|
|
|
|
qualifiers = [
|
|
|
|
(Qualifiers.CONST, "const"),
|
|
|
|
(Qualifiers.VOLATILE, "volatile"),
|
|
|
|
(Qualifiers.RESTRICT, "restrict"),
|
|
|
|
(Qualifiers.ATOMIC, "_Atomic"),
|
|
|
|
]
|
|
|
|
for qualifier in qualifiers:
|
|
|
|
t = constructor(*args, qualifiers=qualifier[0])
|
|
|
|
self.assertTypeName(t, qualifier[1] + " " + expected, same_as_definition)
|
|
|
|
|
|
|
|
# All qualifiers.
|
|
|
|
t = constructor(
|
|
|
|
*args,
|
2021-02-22 00:11:19 +00:00
|
|
|
qualifiers=reduce(operator.or_, (qualifier[0] for qualifier in qualifiers)),
|
2020-01-14 19:43:58 +00:00
|
|
|
)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
|
|
|
t,
|
|
|
|
" ".join(qualifier[1] for qualifier in qualifiers) + " " + expected,
|
|
|
|
same_as_definition,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_void(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.assertQualifiedTypeName("void", True, self.prog.void_type)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
|
|
|
|
def test_int(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.assertQualifiedTypeName("int", True, self.prog.int_type, "int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
|
|
|
|
def test_bool(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.assertQualifiedTypeName("_Bool", True, self.prog.bool_type, "_Bool", 1)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
|
|
|
|
def test_float(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.assertQualifiedTypeName("float", True, self.prog.float_type, "float", 4)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
|
|
|
|
def test_struct(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.assertQualifiedTypeName(
|
|
|
|
"struct point", True, self.prog.struct_type, "point"
|
|
|
|
)
|
|
|
|
self.assertQualifiedTypeName(
|
|
|
|
"struct <anonymous>", False, self.prog.struct_type, None
|
|
|
|
)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
|
|
|
|
def test_union(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.assertQualifiedTypeName(
|
|
|
|
"union option", True, self.prog.union_type, "option"
|
|
|
|
),
|
|
|
|
self.assertQualifiedTypeName(
|
|
|
|
"union <anonymous>", False, self.prog.union_type, None
|
|
|
|
)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
|
2019-11-15 01:12:47 +00:00
|
|
|
def test_class(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.assertQualifiedTypeName("class coord", True, self.prog.class_type, "coord")
|
|
|
|
self.assertQualifiedTypeName(
|
|
|
|
"class <anonymous>", False, self.prog.class_type, None
|
|
|
|
)
|
2019-11-15 01:12:47 +00:00
|
|
|
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
def test_enum(self):
|
|
|
|
self.assertQualifiedTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
"enum color", True, self.prog.enum_type, "color", None, None
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
),
|
|
|
|
self.assertQualifiedTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
"enum <anonymous>", False, self.prog.enum_type, None, None, None
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_typedef(self):
|
|
|
|
self.assertQualifiedTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
"bool",
|
|
|
|
False,
|
|
|
|
self.prog.typedef_type,
|
|
|
|
"bool",
|
|
|
|
self.prog.bool_type("_Bool", 1),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.assertTypeName(
|
|
|
|
self.prog.pointer_type(self.prog.void_type()), "void *", True
|
|
|
|
)
|
|
|
|
t = self.prog.pointer_type(self.prog.void_type(qualifiers=Qualifiers.VOLATILE))
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(t, "volatile void *", True)
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
t = self.prog.pointer_type(
|
|
|
|
self.prog.void_type(qualifiers=Qualifiers.VOLATILE),
|
|
|
|
qualifiers=Qualifiers.CONST,
|
|
|
|
)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(t, "volatile void * const", True)
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
t = self.prog.pointer_type(t)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(t, "volatile void * const *", True)
|
|
|
|
|
|
|
|
def test_array(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
|
|
|
self.assertTypeName(self.prog.array_type(i), "int []", True)
|
|
|
|
self.assertTypeName(self.prog.array_type(i, 2), "int [2]", True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.array_type(self.prog.array_type(i, 3), 2), "int [2][3]", True
|
|
|
|
)
|
|
|
|
self.assertTypeName(
|
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.array_type(self.prog.array_type(i, 4), 3), 2
|
|
|
|
),
|
|
|
|
"int [2][3][4]",
|
|
|
|
True,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_array_of_pointers(self):
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.pointer_type(self.prog.int_type("int", 4, True)), 3
|
|
|
|
),
|
|
|
|
2,
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int *[2][3]",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_array(self):
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.array_type(self.prog.int_type("int", 4, True), 2)
|
|
|
|
),
|
|
|
|
"int (*)[2]",
|
|
|
|
True,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_pointer_to_array(self):
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.array_type(self.prog.int_type("int", 4, True), 2)
|
|
|
|
)
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int (**)[2]",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_array_of_pointers(self):
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.pointer_type(self.prog.int_type("int", 4, True)), 2
|
|
|
|
)
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int *(*)[2]",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_array_of_pointers_to_array(self):
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.array_type(self.prog.int_type("int", 4, True), 3)
|
|
|
|
),
|
|
|
|
2,
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int (*[2])[3]",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_function(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(i, (TypeParameter(i),), False)
|
|
|
|
),
|
2020-02-12 20:04:36 +00:00
|
|
|
"int (*)(int)",
|
|
|
|
True,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(i, (TypeParameter(i, "x"),), False)
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int (*)(int x)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(
|
|
|
|
i,
|
|
|
|
(
|
|
|
|
TypeParameter(i),
|
2020-08-27 06:15:04 +01:00
|
|
|
TypeParameter(self.prog.float_type("float", 4)),
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
),
|
|
|
|
False,
|
2020-02-12 20:04:36 +00:00
|
|
|
),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int (*)(int, float)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_function_returning_pointer(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(
|
|
|
|
self.prog.pointer_type(i), (TypeParameter(i),), False
|
|
|
|
)
|
2020-02-12 20:04:36 +00:00
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int *(*)(int)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(
|
|
|
|
self.prog.pointer_type(i),
|
|
|
|
(TypeParameter(self.prog.pointer_type(i)),),
|
|
|
|
False,
|
2020-02-12 20:04:36 +00:00
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
),
|
|
|
|
"int *(*)(int *)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_function_returning_pointer_to_const(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(
|
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.int_type("int", 4, True, qualifiers=Qualifiers.CONST)
|
|
|
|
),
|
2020-02-12 20:04:36 +00:00
|
|
|
(TypeParameter(i),),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
False,
|
|
|
|
),
|
2020-01-14 19:43:58 +00:00
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"const int *(*)(int)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_function_returning_const_pointer(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(
|
|
|
|
self.prog.pointer_type(i, qualifiers=Qualifiers.CONST),
|
|
|
|
(TypeParameter(i),),
|
|
|
|
False,
|
2020-02-12 20:04:36 +00:00
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
),
|
|
|
|
"int * const (*)(int)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_const_pointer_to_function_returning_pointer(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(
|
|
|
|
self.prog.pointer_type(i), (TypeParameter(i),), False
|
|
|
|
),
|
|
|
|
qualifiers=Qualifiers.CONST,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
),
|
|
|
|
"int *(* const)(int)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_array_of_pointers_to_functions(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(i, (TypeParameter(i),), False)
|
|
|
|
),
|
|
|
|
4,
|
2020-02-12 20:04:36 +00:00
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int (*[4])(int)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_array_of_const_pointers_to_functions(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(i, (TypeParameter(i),), False),
|
|
|
|
qualifiers=Qualifiers.CONST,
|
2020-02-12 20:04:36 +00:00
|
|
|
),
|
2020-01-14 19:43:58 +00:00
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int (* const [])(int)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_variadic_function(self):
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
i = self.prog.int_type("int", 4, True)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(i, (TypeParameter(i),), True)
|
|
|
|
),
|
2020-02-12 20:04:36 +00:00
|
|
|
"int (*)(int, ...)",
|
|
|
|
True,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_function_with_no_parameters(self):
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(self.prog.int_type("int", 4, True), (), False)
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int (*)(void)",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_to_function_with_no_parameter_specification(self):
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.function_type(self.prog.int_type("int", 4, True), (), True)
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"int (*)()",
|
|
|
|
True,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_function(self):
|
|
|
|
self.assertTypeName(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.function_type(self.prog.int_type("int", 4, True), (), False),
|
|
|
|
"int (void)",
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
|
2021-11-23 08:52:39 +00:00
|
|
|
def test_pointer_to_anonymous_struct(self):
|
|
|
|
self.assertTypeName(
|
|
|
|
self.prog.pointer_type(
|
|
|
|
self.prog.struct_type(
|
|
|
|
None, 8, (TypeMember(self.prog.int_type("int", 4, True), "x", 0),)
|
|
|
|
)
|
|
|
|
),
|
|
|
|
"struct <anonymous> *",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_array_of_anonymous_struct(self):
|
|
|
|
self.assertTypeName(
|
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.struct_type(
|
|
|
|
None, 8, (TypeMember(self.prog.int_type("int", 4, True), "x", 0),)
|
|
|
|
),
|
|
|
|
2,
|
|
|
|
),
|
|
|
|
"struct <anonymous> [2]",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_function_returning_anonymous_struct(self):
|
|
|
|
self.assertTypeName(
|
|
|
|
self.prog.function_type(
|
|
|
|
self.prog.struct_type(
|
|
|
|
None, 8, (TypeMember(self.prog.int_type("int", 4, True), "x", 0),)
|
|
|
|
),
|
|
|
|
(),
|
|
|
|
),
|
|
|
|
"struct <anonymous> (void)",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_function_of_anonymous_struct(self):
|
|
|
|
self.assertTypeName(
|
|
|
|
self.prog.function_type(
|
|
|
|
self.prog.int_type("int", 4, True),
|
|
|
|
(
|
|
|
|
TypeParameter(
|
|
|
|
self.prog.struct_type(
|
|
|
|
None,
|
|
|
|
8,
|
|
|
|
(TypeMember(self.prog.int_type("int", 4, True), "x", 0),),
|
|
|
|
),
|
|
|
|
"x",
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
"int (struct <anonymous> x)",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_typedef_of_anonymous_struct(self):
|
|
|
|
self.assertTypeName(
|
|
|
|
self.prog.typedef_type(
|
|
|
|
"onymous",
|
|
|
|
self.prog.struct_type(
|
|
|
|
None, 8, (TypeMember(self.prog.int_type("int", 4, True), "x", 0),)
|
|
|
|
),
|
|
|
|
),
|
|
|
|
"onymous",
|
|
|
|
)
|
|
|
|
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
class TestPrettyPrintType(MockProgramTestCase):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
def assertPrettyPrint(self, type, expected):
|
|
|
|
self.assertEqual(str(type), expected)
|
|
|
|
|
|
|
|
def test_struct(self):
|
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.point_type,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
struct point {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
}""",
|
|
|
|
)
|
2020-01-14 19:43:58 +00:00
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_struct_member(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.line_segment_type,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
struct line_segment {
|
|
|
|
struct point a;
|
|
|
|
struct point b;
|
|
|
|
}""",
|
|
|
|
)
|
2020-01-14 19:43:58 +00:00
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_anonymous_struct(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.struct_type(
|
|
|
|
None,
|
|
|
|
8,
|
|
|
|
(
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "x", 0),
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "y", 32),
|
|
|
|
),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
struct {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_anonymous_struct_member(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
# Member with anonymous struct type.
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
anonymous_struct = self.prog.struct_type(
|
|
|
|
None,
|
|
|
|
8,
|
|
|
|
(
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "x", 0),
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "y", 32),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.struct_type(
|
|
|
|
"line_segment",
|
|
|
|
16,
|
|
|
|
(
|
|
|
|
TypeMember(anonymous_struct, "a", 0),
|
|
|
|
TypeMember(anonymous_struct, "b", 64),
|
|
|
|
),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
struct line_segment {
|
|
|
|
struct {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
} a;
|
|
|
|
struct {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
} b;
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_struct_unnamed_member(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.struct_type(
|
|
|
|
"point3",
|
|
|
|
0,
|
|
|
|
(
|
|
|
|
TypeMember(
|
|
|
|
self.prog.struct_type(
|
|
|
|
None,
|
|
|
|
8,
|
|
|
|
(
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "x"),
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "y", 32),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
),
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "z", 64),
|
|
|
|
),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
struct point3 {
|
|
|
|
struct {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
};
|
|
|
|
int z;
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_bit_field(self):
|
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.struct_type(
|
|
|
|
"point",
|
|
|
|
4,
|
|
|
|
(
|
2020-12-18 19:01:29 +00:00
|
|
|
TypeMember(
|
|
|
|
Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.int_type("int", 4, True),
|
|
|
|
bit_field_size=4,
|
|
|
|
),
|
|
|
|
"x",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
TypeMember(
|
|
|
|
Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.int_type("int", 4, True),
|
|
|
|
bit_field_size=8,
|
|
|
|
),
|
|
|
|
"y",
|
|
|
|
4,
|
|
|
|
),
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
struct point {
|
|
|
|
int x : 4;
|
|
|
|
int y : 8;
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_union(self):
|
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.union_type(
|
|
|
|
"foo",
|
|
|
|
4,
|
|
|
|
(
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "i"),
|
|
|
|
TypeMember(
|
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.int_type("unsigned char", 1, False), 4
|
|
|
|
),
|
|
|
|
"a",
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
union foo {
|
|
|
|
int i;
|
|
|
|
unsigned char a[4];
|
|
|
|
}""",
|
|
|
|
)
|
2020-01-14 19:43:58 +00:00
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_union_qualified(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.union_type(
|
|
|
|
"foo",
|
|
|
|
4,
|
|
|
|
(
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "i"),
|
|
|
|
TypeMember(
|
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.int_type("unsigned char", 1, False), 4
|
|
|
|
),
|
|
|
|
"a",
|
|
|
|
),
|
|
|
|
),
|
|
|
|
qualifiers=Qualifiers.CONST,
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
const union foo {
|
|
|
|
int i;
|
|
|
|
unsigned char a[4];
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
2019-11-15 01:12:47 +00:00
|
|
|
def test_class(self):
|
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.coord_type,
|
2019-11-15 01:12:47 +00:00
|
|
|
"""\
|
|
|
|
class coord {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
int z;
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
def test_enum(self):
|
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.color_type,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
enum color {
|
|
|
|
RED = 0,
|
|
|
|
GREEN = 1,
|
|
|
|
BLUE = 2,
|
|
|
|
}""",
|
|
|
|
)
|
2020-01-14 19:43:58 +00:00
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_enum_qualified(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.color_type.qualified(Qualifiers.CONST),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
const enum color {
|
|
|
|
RED = 0,
|
|
|
|
GREEN = 1,
|
|
|
|
BLUE = 2,
|
|
|
|
}""",
|
|
|
|
)
|
2020-01-14 19:43:58 +00:00
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_enum_anonymous(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.enum_type(
|
|
|
|
None,
|
|
|
|
self.prog.int_type("int", 4, True),
|
|
|
|
(
|
|
|
|
TypeEnumerator("RED", 0),
|
|
|
|
TypeEnumerator("GREEN", -1),
|
|
|
|
TypeEnumerator("BLUE", -2),
|
|
|
|
),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
enum {
|
|
|
|
RED = 0,
|
|
|
|
GREEN = -1,
|
|
|
|
BLUE = -2,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_typedef(self):
|
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.typedef_type("INT", self.prog.int_type("int", 4, True)),
|
|
|
|
"typedef int INT",
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
|
|
|
|
def test_typedef_const(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.typedef_type(
|
|
|
|
"CINT", self.prog.int_type("int", 4, True, qualifiers=Qualifiers.CONST)
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"typedef const int CINT",
|
|
|
|
)
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
|
|
|
|
def test_const_typedef(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.typedef_type(
|
|
|
|
"INT", self.prog.int_type("int", 4, True), qualifiers=Qualifiers.CONST
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"const typedef int INT",
|
|
|
|
)
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
|
|
|
|
def test_typedef_pointer(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.typedef_type(
|
|
|
|
"string", self.prog.pointer_type(self.prog.int_type("char", 1, True))
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"typedef char *string",
|
|
|
|
)
|
2020-01-14 19:43:58 +00:00
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_typedef_struct(self):
|
|
|
|
self.assertPrettyPrint(
|
|
|
|
self.prog.typedef_type(
|
|
|
|
"Point",
|
|
|
|
self.prog.struct_type(
|
|
|
|
None,
|
|
|
|
8,
|
|
|
|
(
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "x", 0),
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "y", 32),
|
|
|
|
),
|
2020-01-14 19:43:58 +00:00
|
|
|
),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"""\
|
|
|
|
typedef struct {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
} Point""",
|
|
|
|
)
|
|
|
|
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
def test_typedef_function(self):
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
self.assertPrettyPrint(
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.typedef_type(
|
|
|
|
"fn",
|
|
|
|
self.prog.function_type(self.prog.int_type("int", 4, True), (), False),
|
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
"typedef int fn(void)",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_function_no_name(self):
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
ValueError,
|
|
|
|
"function must have name",
|
|
|
|
str,
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
self.prog.struct_type(
|
2020-02-12 20:04:36 +00:00
|
|
|
"foo",
|
|
|
|
8,
|
Associate types with program
I originally envisioned types as dumb descriptors. This mostly works for
C because in C, types are fairly simple. However, even then the
drgn_program_member_info() API is awkward. You should be able to look up
a member directly from a type, but we need the program for caching
purposes. This has also held me back from adding offsetof() or
has_member() APIs.
Things get even messier with C++. C++ template parameters can be objects
(e.g., template <int N>). Such parameters would best be represented by a
drgn object, which we need a drgn program for. Static members are a
similar case.
So, let's reimagine types as being owned by a program. This has a few
parts:
1. In libdrgn, simple types are now created by factory functions,
drgn_foo_type_create().
2. To handle their variable length fields, compound types, enum types,
and function types are constructed with a "builder" API.
3. Simple types are deduplicated.
4. The Python type factory functions are replaced by methods of the
Program class.
5. While we're changing the API, the parameters to pointer_type() and
array_type() are reordered to be more logical (and to allow
pointer_type() to take a default size of None for the program's
default pointer size).
6. Likewise, the type factory methods take qualifiers as a keyword
argument only.
A big part of this change is updating the tests and splitting up large
test cases into smaller ones in a few places.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-07-16 00:34:56 +01:00
|
|
|
(
|
|
|
|
TypeMember(
|
|
|
|
self.prog.function_type(
|
|
|
|
self.prog.int_type("int", 4, True), (), False
|
|
|
|
)
|
|
|
|
),
|
|
|
|
),
|
2020-01-14 19:43:58 +00:00
|
|
|
),
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-01-07 22:28:01 +00:00
|
|
|
class TestLexer(TestCase):
|
2022-02-18 06:18:53 +00:00
|
|
|
def lex(self, s, cpp=False):
|
|
|
|
lexer = Lexer(drgn_c_family_lexer_func, s, cpp)
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
while True:
|
|
|
|
token = lexer.pop()
|
|
|
|
if token.kind == C_TOKEN.EOF:
|
|
|
|
break
|
|
|
|
yield token
|
|
|
|
|
|
|
|
def test_empty(self):
|
2022-02-18 06:18:53 +00:00
|
|
|
lexer = Lexer(drgn_c_family_lexer_func, "")
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
for i in range(64):
|
|
|
|
self.assertEqual(lexer.pop().kind, C_TOKEN.EOF)
|
|
|
|
|
|
|
|
def test_symbols(self):
|
|
|
|
s = "()[]*."
|
|
|
|
tokens = [
|
|
|
|
C_TOKEN.LPAREN,
|
|
|
|
C_TOKEN.RPAREN,
|
|
|
|
C_TOKEN.LBRACKET,
|
|
|
|
C_TOKEN.RBRACKET,
|
|
|
|
C_TOKEN.ASTERISK,
|
|
|
|
C_TOKEN.DOT,
|
|
|
|
]
|
|
|
|
self.assertEqual([token.kind for token in self.lex(s)], tokens)
|
|
|
|
|
|
|
|
def test_keywords(self):
|
|
|
|
s = """void char short int long signed unsigned _Bool float double
|
2022-02-18 06:18:53 +00:00
|
|
|
_Complex const restrict volatile _Atomic struct union class enum"""
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
tokens = [
|
|
|
|
C_TOKEN.VOID,
|
|
|
|
C_TOKEN.CHAR,
|
|
|
|
C_TOKEN.SHORT,
|
|
|
|
C_TOKEN.INT,
|
|
|
|
C_TOKEN.LONG,
|
|
|
|
C_TOKEN.SIGNED,
|
|
|
|
C_TOKEN.UNSIGNED,
|
|
|
|
C_TOKEN.BOOL,
|
|
|
|
C_TOKEN.FLOAT,
|
|
|
|
C_TOKEN.DOUBLE,
|
|
|
|
C_TOKEN.COMPLEX,
|
|
|
|
C_TOKEN.CONST,
|
|
|
|
C_TOKEN.RESTRICT,
|
|
|
|
C_TOKEN.VOLATILE,
|
|
|
|
C_TOKEN.ATOMIC,
|
|
|
|
C_TOKEN.STRUCT,
|
|
|
|
C_TOKEN.UNION,
|
2022-02-18 06:18:53 +00:00
|
|
|
C_TOKEN.IDENTIFIER,
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
C_TOKEN.ENUM,
|
|
|
|
]
|
|
|
|
self.assertEqual([token.kind for token in self.lex(s)], tokens)
|
|
|
|
|
2022-02-18 06:18:53 +00:00
|
|
|
def test_cpp_keywords(self):
|
|
|
|
s = """void char short int long signed unsigned _Bool float double
|
|
|
|
_Complex const restrict volatile _Atomic struct union class enum"""
|
|
|
|
tokens = [
|
|
|
|
C_TOKEN.VOID,
|
|
|
|
C_TOKEN.CHAR,
|
|
|
|
C_TOKEN.SHORT,
|
|
|
|
C_TOKEN.INT,
|
|
|
|
C_TOKEN.LONG,
|
|
|
|
C_TOKEN.SIGNED,
|
|
|
|
C_TOKEN.UNSIGNED,
|
|
|
|
C_TOKEN.BOOL,
|
|
|
|
C_TOKEN.FLOAT,
|
|
|
|
C_TOKEN.DOUBLE,
|
|
|
|
C_TOKEN.COMPLEX,
|
|
|
|
C_TOKEN.CONST,
|
|
|
|
C_TOKEN.RESTRICT,
|
|
|
|
C_TOKEN.VOLATILE,
|
|
|
|
C_TOKEN.ATOMIC,
|
|
|
|
C_TOKEN.STRUCT,
|
|
|
|
C_TOKEN.UNION,
|
|
|
|
C_TOKEN.CLASS,
|
|
|
|
C_TOKEN.ENUM,
|
|
|
|
]
|
|
|
|
self.assertEqual([token.kind for token in self.lex(s, cpp=True)], tokens)
|
|
|
|
|
2022-11-30 21:52:25 +00:00
|
|
|
def test_cpp_identifiers_with_template_parameters(self):
|
|
|
|
token_pairs = (
|
|
|
|
("vector", "<int>"),
|
|
|
|
("pair", "<int, double>"),
|
|
|
|
("unordered_map", "<std::string, std::vector<pair<short, bool>>>"),
|
|
|
|
("IntLiteral", "<123>"),
|
|
|
|
("IntLiteralWithSuffix", "<123UL>"),
|
|
|
|
("FloatLiteral", "<1.987>"),
|
|
|
|
("FloatLiteralWithExponent", "<1.23423e+1f>"),
|
|
|
|
("PointerLiteral", "<&asdf>"),
|
|
|
|
("ParenthesizedPointerLiteral", "<(&asdf)>"),
|
|
|
|
("CharLiteral", "<'a'>"),
|
|
|
|
("CharLiteralEdgeCase1", "<'<'>"),
|
|
|
|
("CharLiteralEdgeCase2", "<'>'>"),
|
|
|
|
("CharLiteralEdgeCase3", r"<'\''>"),
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
[
|
|
|
|
(token.kind, token.value)
|
|
|
|
for token in self.lex(
|
|
|
|
" ".join("".join(pair) for pair in token_pairs), cpp=True
|
|
|
|
)
|
|
|
|
],
|
|
|
|
[
|
|
|
|
(C_TOKEN.TEMPLATE_ARGUMENTS if i % 2 else C_TOKEN.IDENTIFIER, value)
|
|
|
|
for i, value in enumerate(chain.from_iterable(token_pairs))
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_cpp_identifiers_with_invalid_template_parameters(self):
|
|
|
|
for s in [
|
|
|
|
"vector<int",
|
|
|
|
"pair<<int, double>",
|
|
|
|
"unordered_map<string, vector<pair<short, bool>>",
|
|
|
|
]:
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
SyntaxError,
|
|
|
|
"invalid template arguments",
|
|
|
|
list,
|
|
|
|
self.lex(s, cpp=True),
|
|
|
|
)
|
|
|
|
for s in [
|
|
|
|
"vectorint>",
|
|
|
|
"pair<int, double>>",
|
|
|
|
]:
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
SyntaxError,
|
|
|
|
"invalid character",
|
|
|
|
list,
|
|
|
|
self.lex(s, cpp=True),
|
|
|
|
)
|
|
|
|
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
def test_identifiers(self):
|
|
|
|
s = "_ x foo _bar baz1"
|
|
|
|
tokens = s.split()
|
|
|
|
self.assertEqual(
|
|
|
|
[(token.kind, token.value) for token in self.lex(s)],
|
|
|
|
[(C_TOKEN.IDENTIFIER, value) for value in tokens],
|
|
|
|
)
|
|
|
|
|
2022-02-05 01:17:31 +00:00
|
|
|
def test_almost_keywords(self):
|
|
|
|
s = """voi cha shor in lon signe unsigne _Boo floa doubl
|
|
|
|
_Comple cons restric volatil _Atomi struc unio enu"""
|
|
|
|
tokens = s.split()
|
|
|
|
self.assertEqual(
|
|
|
|
[(token.kind, token.value) for token in self.lex(s)],
|
|
|
|
[(C_TOKEN.IDENTIFIER, value) for value in tokens],
|
|
|
|
)
|
|
|
|
|
Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:
- It's too slow for some common use cases, like iterating over large
data structures.
- It can't be reused in utilities written in other languages.
This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:
- Types are now represented by a single Type class rather than the messy
polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
functions.
The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.
Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-03-22 23:27:46 +00:00
|
|
|
def test_number(self):
|
|
|
|
s = "0 1234 0xdeadbeef"
|
|
|
|
tokens = s.split()
|
|
|
|
self.assertEqual(
|
|
|
|
[(token.kind, token.value) for token in self.lex(s)],
|
|
|
|
[(C_TOKEN.NUMBER, value) for value in tokens],
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_invalid_number(self):
|
|
|
|
for s in ["0x", "1234y"]:
|
|
|
|
self.assertRaisesRegex(SyntaxError, "invalid number", list, self.lex(s))
|
|
|
|
|
|
|
|
def test_invalid_character(self):
|
|
|
|
self.assertRaisesRegex(SyntaxError, "invalid character", list, self.lex("@"))
|
2021-02-22 00:11:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TestLiteral(MockProgramTestCase):
|
|
|
|
def test_int(self):
|
|
|
|
self.assertIdentical(
|
|
|
|
Object(self.prog, value=1), Object(self.prog, "int", value=1)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
Object(self.prog, value=-1), Object(self.prog, "int", value=-1)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
2022-02-12 21:48:49 +00:00
|
|
|
Object(self.prog, value=2**31 - 1),
|
|
|
|
Object(self.prog, "int", value=2**31 - 1),
|
2021-02-22 00:11:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
2022-02-12 21:48:49 +00:00
|
|
|
Object(self.prog, value=2**31), Object(self.prog, "long", value=2**31)
|
2021-02-22 00:11:19 +00:00
|
|
|
)
|
|
|
|
# Not int, because this is treated as the negation operator applied to
|
|
|
|
# 2**31.
|
|
|
|
self.assertIdentical(
|
2022-02-12 21:48:49 +00:00
|
|
|
Object(self.prog, value=-(2**31)),
|
|
|
|
Object(self.prog, "long", value=-(2**31)),
|
2021-02-22 00:11:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
2022-02-12 21:48:49 +00:00
|
|
|
Object(self.prog, value=2**63),
|
|
|
|
Object(self.prog, "unsigned long long", value=2**63),
|
2021-02-22 00:11:19 +00:00
|
|
|
)
|
|
|
|
self.assertIdentical(
|
2022-02-12 21:48:49 +00:00
|
|
|
Object(self.prog, value=2**64 - 1),
|
|
|
|
Object(self.prog, "unsigned long long", value=2**64 - 1),
|
2021-02-22 00:11:19 +00:00
|
|
|
)
|
|
|
|
self.assertIdentical(
|
2022-02-12 21:48:49 +00:00
|
|
|
Object(self.prog, value=-(2**64 - 1)),
|
2021-02-22 00:11:19 +00:00
|
|
|
Object(self.prog, "unsigned long long", value=1),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_bool(self):
|
|
|
|
self.assertIdentical(
|
|
|
|
Object(self.prog, value=True), Object(self.prog, "int", value=1)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
Object(self.prog, value=False), Object(self.prog, "int", value=0)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_float(self):
|
|
|
|
self.assertIdentical(
|
|
|
|
Object(self.prog, value=3.14), Object(self.prog, "double", value=3.14)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_invalid(self):
|
|
|
|
class Foo:
|
|
|
|
pass
|
|
|
|
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError, "cannot create Foo literal", Object, self.prog, value=Foo()
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class TestIntegerPromotion(MockProgramTestCase):
|
|
|
|
def test_conversion_rank_less_than_int(self):
|
|
|
|
self.assertIdentical(+self.bool(False), self.int(0))
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "char", value=1), Object(self.prog, "int", value=1)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "signed char", value=2),
|
|
|
|
Object(self.prog, "int", value=2),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned char", value=3),
|
|
|
|
Object(self.prog, "int", value=3),
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "short", value=1), Object(self.prog, "int", value=1)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned short", value=2),
|
|
|
|
Object(self.prog, "int", value=2),
|
|
|
|
)
|
|
|
|
|
|
|
|
# If short is the same size as int, then int can't represent all of the
|
|
|
|
# values of unsigned short.
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, self.prog.int_type("short", 4, True), value=1),
|
|
|
|
Object(self.prog, "int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, self.prog.int_type("unsigned short", 4, False), value=2),
|
|
|
|
Object(self.prog, "unsigned int", value=2),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_int(self):
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "int", value=-1), Object(self.prog, "int", value=-1)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned int", value=-1),
|
|
|
|
Object(self.prog, "unsigned int", value=-1),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_conversion_rank_greater_than_int(self):
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "long", value=-1), Object(self.prog, "long", value=-1)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned long", value=-1),
|
|
|
|
Object(self.prog, "unsigned long", value=-1),
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "long long", value=-1),
|
|
|
|
Object(self.prog, "long long", value=-1),
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned long long", value=-1),
|
|
|
|
Object(self.prog, "unsigned long long", value=-1),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_extended_integer(self):
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, self.prog.int_type("byte", 1, True), value=1),
|
|
|
|
Object(self.prog, "int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, self.prog.int_type("ubyte", 1, False), value=-1),
|
|
|
|
Object(self.prog, "int", value=0xFF),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, self.prog.int_type("qword", 8, True), value=1),
|
|
|
|
Object(self.prog, self.prog.int_type("qword", 8, True), value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, self.prog.int_type("qword", 8, False), value=1),
|
|
|
|
Object(self.prog, self.prog.int_type("qword", 8, False), value=1),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_bit_field(self):
|
|
|
|
# Bit fields which can be represented by int or unsigned int should be
|
|
|
|
# promoted.
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "int", value=1, bit_field_size=4),
|
|
|
|
Object(self.prog, "int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "long", value=1, bit_field_size=4),
|
|
|
|
Object(self.prog, "int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "int", value=1, bit_field_size=32),
|
|
|
|
Object(self.prog, "int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "long", value=1, bit_field_size=32),
|
|
|
|
Object(self.prog, "int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned int", value=1, bit_field_size=4),
|
|
|
|
Object(self.prog, "int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned long", value=1, bit_field_size=4),
|
|
|
|
Object(self.prog, "int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned int", value=1, bit_field_size=32),
|
|
|
|
Object(self.prog, "unsigned int", value=1),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned long", value=1, bit_field_size=32),
|
|
|
|
Object(self.prog, "unsigned int", value=1),
|
|
|
|
)
|
|
|
|
|
|
|
|
# Bit fields which cannot be represented by int or unsigned int should
|
|
|
|
# be preserved.
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "long", value=1, bit_field_size=40),
|
|
|
|
Object(self.prog, "long", value=1, bit_field_size=40),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "unsigned long", value=1, bit_field_size=40),
|
|
|
|
Object(self.prog, "unsigned long", value=1, bit_field_size=40),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_enum(self):
|
|
|
|
# Enums should be converted to their compatible type and then promoted.
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, self.color_type, value=1),
|
|
|
|
Object(self.prog, "unsigned int", value=1),
|
|
|
|
)
|
|
|
|
|
|
|
|
type_ = self.prog.enum_type(
|
|
|
|
"color",
|
|
|
|
self.prog.type("unsigned long long"),
|
|
|
|
(
|
|
|
|
TypeEnumerator("RED", 0),
|
|
|
|
TypeEnumerator("GREEN", 1),
|
|
|
|
TypeEnumerator("BLUE", 2),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, type_, value=1),
|
|
|
|
Object(self.prog, "unsigned long long", value=1),
|
|
|
|
)
|
|
|
|
|
|
|
|
type_ = self.prog.enum_type(
|
|
|
|
"color",
|
|
|
|
self.prog.type("char"),
|
|
|
|
(
|
|
|
|
TypeEnumerator("RED", 0),
|
|
|
|
TypeEnumerator("GREEN", 1),
|
|
|
|
TypeEnumerator("BLUE", 2),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, type_, value=1), Object(self.prog, "int", value=1)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_typedef(self):
|
|
|
|
type_ = self.prog.typedef_type("SHORT", self.prog.type("short"))
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, type_, value=5), Object(self.prog, "int", value=5)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Typedef should be preserved if the type wasn't promoted.
|
|
|
|
type_ = self.prog.typedef_type("CINT", self.prog.type("int"))
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, type_, value=5), Object(self.prog, type_, value=5)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_non_integer(self):
|
|
|
|
# Non-integer types should not be affected.
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, "double", value=3.14),
|
|
|
|
Object(self.prog, "double", value=3.14),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_byte_order(self):
|
|
|
|
# Types in the opposite byte order should converted to the program's
|
|
|
|
# byte order.
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(self.prog, self.prog.int_type("int", 4, True, "big"), value=5),
|
|
|
|
Object(self.prog, self.prog.int_type("int", 4, True, "little"), value=5),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_byte_order_typedef(self):
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.typedef_type(
|
|
|
|
"CINT", self.prog.int_type("int", 4, True, "big")
|
|
|
|
),
|
|
|
|
value=5,
|
|
|
|
),
|
|
|
|
Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.typedef_type(
|
|
|
|
"CINT", self.prog.int_type("int", 4, True, "little")
|
|
|
|
),
|
|
|
|
value=5,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_byte_order_enum(self):
|
|
|
|
self.assertIdentical(
|
|
|
|
+Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.enum_type(
|
|
|
|
"ENUM", self.prog.int_type("int", 4, True, "big"), ()
|
|
|
|
),
|
|
|
|
value=5,
|
|
|
|
),
|
|
|
|
Object(self.prog, self.prog.int_type("int", 4, True, "little"), value=5),
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class TestCommonRealType(MockProgramTestCase):
|
|
|
|
def assertCommonRealType(self, lhs, rhs, expected, commutative=True):
|
|
|
|
if isinstance(lhs, (str, Type)):
|
|
|
|
obj1 = Object(self.prog, lhs, value=1)
|
|
|
|
else:
|
|
|
|
obj1 = Object(self.prog, lhs[0], value=1, bit_field_size=lhs[1])
|
|
|
|
if isinstance(rhs, (str, Type)):
|
|
|
|
obj2 = Object(self.prog, rhs, value=1)
|
|
|
|
else:
|
|
|
|
obj2 = Object(self.prog, rhs[0], value=1, bit_field_size=rhs[1])
|
|
|
|
if isinstance(expected, (str, Type)):
|
|
|
|
expected_obj = Object(self.prog, expected, value=1)
|
|
|
|
else:
|
|
|
|
expected_obj = Object(
|
|
|
|
self.prog, expected[0], value=1, bit_field_size=expected[1]
|
|
|
|
)
|
|
|
|
self.assertIdentical(obj1 * obj2, expected_obj)
|
|
|
|
if commutative:
|
|
|
|
self.assertIdentical(obj2 * obj1, expected_obj)
|
|
|
|
|
|
|
|
def test_float(self):
|
|
|
|
self.assertCommonRealType("float", "long long", "float")
|
|
|
|
self.assertCommonRealType("float", "float", "float")
|
|
|
|
|
|
|
|
self.assertCommonRealType("double", "long long", "double")
|
|
|
|
self.assertCommonRealType("double", "float", "double")
|
|
|
|
self.assertCommonRealType("double", "double", "double")
|
|
|
|
|
|
|
|
# Floating type not in the standard.
|
|
|
|
float64 = self.prog.float_type("float64", 8)
|
|
|
|
self.assertCommonRealType(float64, "long long", float64)
|
|
|
|
self.assertCommonRealType(float64, "float", float64)
|
|
|
|
self.assertCommonRealType(float64, "double", float64)
|
|
|
|
self.assertCommonRealType(float64, float64, float64)
|
|
|
|
|
|
|
|
def test_bit_field(self):
|
|
|
|
# Same width and sign.
|
|
|
|
self.assertCommonRealType(
|
|
|
|
("long long", 33), ("long long", 33), ("long long", 33)
|
|
|
|
)
|
|
|
|
self.assertCommonRealType(
|
|
|
|
("long long", 33), ("long", 33), ("long", 33), commutative=False
|
|
|
|
)
|
|
|
|
self.assertCommonRealType(
|
|
|
|
("long", 33), ("long long", 33), ("long long", 33), commutative=False
|
|
|
|
)
|
|
|
|
|
|
|
|
# Same width, different sign.
|
|
|
|
self.assertCommonRealType(
|
|
|
|
("long long", 33), ("unsigned long long", 33), ("unsigned long long", 33)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Different width, same sign.
|
|
|
|
self.assertCommonRealType(
|
|
|
|
("long long", 34), ("long long", 33), ("long long", 34)
|
|
|
|
)
|
|
|
|
|
|
|
|
# Different width, different sign.
|
|
|
|
self.assertCommonRealType(
|
|
|
|
("long long", 34), ("unsigned long long", 33), ("long long", 34)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_same(self):
|
|
|
|
self.assertCommonRealType("_Bool", "_Bool", "int")
|
|
|
|
self.assertCommonRealType("int", "int", "int")
|
|
|
|
self.assertCommonRealType("long", "long", "long")
|
|
|
|
|
|
|
|
def test_same_sign(self):
|
|
|
|
self.assertCommonRealType("long", "int", "long")
|
|
|
|
self.assertCommonRealType("long long", "int", "long long")
|
|
|
|
self.assertCommonRealType("long long", "long", "long long")
|
|
|
|
|
|
|
|
self.assertCommonRealType("unsigned long", "unsigned int", "unsigned long")
|
|
|
|
self.assertCommonRealType(
|
|
|
|
"unsigned long long", "unsigned int", "unsigned long long"
|
|
|
|
)
|
|
|
|
self.assertCommonRealType(
|
|
|
|
"unsigned long long", "unsigned long", "unsigned long long"
|
|
|
|
)
|
|
|
|
|
|
|
|
int64 = self.prog.int_type("int64", 8, True)
|
|
|
|
qword = self.prog.int_type("qword", 8, True)
|
|
|
|
self.assertCommonRealType("long", int64, "long")
|
|
|
|
self.assertCommonRealType(int64, qword, qword, commutative=False)
|
|
|
|
self.assertCommonRealType(qword, int64, int64, commutative=False)
|
|
|
|
self.assertCommonRealType("int", int64, int64)
|
|
|
|
|
|
|
|
def test_unsigned_greater_rank(self):
|
|
|
|
self.assertCommonRealType("unsigned long", "int", "unsigned long")
|
|
|
|
self.assertCommonRealType("unsigned long long", "long", "unsigned long long")
|
|
|
|
self.assertCommonRealType("unsigned long long", "int", "unsigned long long")
|
|
|
|
|
|
|
|
int64 = self.prog.int_type("int64", 8, True)
|
|
|
|
uint64 = self.prog.int_type("uint64", 8, False)
|
|
|
|
self.assertCommonRealType(uint64, "int", uint64)
|
|
|
|
self.assertCommonRealType("unsigned long", int64, "unsigned long")
|
|
|
|
|
|
|
|
def test_signed_can_represent_unsigned(self):
|
|
|
|
self.assertCommonRealType("long", "unsigned int", "long")
|
|
|
|
self.assertCommonRealType("long long", "unsigned int", "long long")
|
|
|
|
|
|
|
|
int64 = self.prog.int_type("int64", 8, True)
|
|
|
|
weirduint = self.prog.int_type("weirduint", 6, False)
|
|
|
|
self.assertCommonRealType(int64, "unsigned int", int64)
|
|
|
|
self.assertCommonRealType("long", weirduint, "long")
|
|
|
|
|
|
|
|
def test_corresponding_unsigned(self):
|
|
|
|
self.assertCommonRealType("long", "unsigned long", "unsigned long")
|
|
|
|
self.assertCommonRealType("long long", "unsigned long", "unsigned long long")
|
|
|
|
|
|
|
|
def test_enum(self):
|
|
|
|
self.assertCommonRealType(self.color_type, self.color_type, "unsigned int")
|
|
|
|
|
|
|
|
def test_typedef(self):
|
|
|
|
type_ = self.prog.typedef_type("INT", self.prog.type("int"))
|
|
|
|
self.assertCommonRealType(type_, type_, type_)
|
|
|
|
self.assertCommonRealType("int", type_, type_, commutative=False)
|
|
|
|
self.assertCommonRealType(type_, "int", "int", commutative=False)
|
|
|
|
|
|
|
|
type_ = self.prog.typedef_type("LONG", self.prog.type("long"))
|
|
|
|
self.assertCommonRealType(type_, "int", type_)
|
|
|
|
|
|
|
|
|
|
|
|
class TestOperators(MockProgramTestCase):
|
|
|
|
def test_cast_array(self):
|
|
|
|
obj = Object(self.prog, "int []", address=0xFFFF0000)
|
|
|
|
self.assertIdentical(
|
|
|
|
cast("int *", obj), Object(self.prog, "int *", value=0xFFFF0000)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
cast("void *", obj), Object(self.prog, "void *", value=0xFFFF0000)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
cast("unsigned long", obj),
|
|
|
|
Object(self.prog, "unsigned long", value=0xFFFF0000),
|
|
|
|
)
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError, r"cannot cast to 'int \[2]'", cast, "int [2]", obj
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_cast_function(self):
|
|
|
|
func = Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.function_type(self.prog.void_type(), (), False),
|
|
|
|
address=0xFFFF0000,
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
cast("void *", func), Object(self.prog, "void *", value=0xFFFF0000)
|
|
|
|
)
|
|
|
|
|
|
|
|
def _test_arithmetic(
|
|
|
|
self, op, lhs, rhs, result, integral=True, floating_point=False
|
|
|
|
):
|
|
|
|
if integral:
|
|
|
|
self.assertIdentical(op(self.int(lhs), self.int(rhs)), self.int(result))
|
|
|
|
self.assertIdentical(op(self.int(lhs), self.long(rhs)), self.long(result))
|
|
|
|
self.assertIdentical(op(self.long(lhs), self.int(rhs)), self.long(result))
|
|
|
|
self.assertIdentical(op(self.long(lhs), self.long(rhs)), self.long(result))
|
|
|
|
self.assertIdentical(op(self.int(lhs), rhs), self.int(result))
|
|
|
|
self.assertIdentical(op(self.long(lhs), rhs), self.long(result))
|
|
|
|
self.assertIdentical(op(lhs, self.int(rhs)), self.int(result))
|
|
|
|
self.assertIdentical(op(lhs, self.long(rhs)), self.long(result))
|
|
|
|
|
|
|
|
if floating_point:
|
|
|
|
self.assertIdentical(
|
|
|
|
op(self.double(lhs), self.double(rhs)), self.double(result)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
op(self.double(lhs), self.int(rhs)), self.double(result)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
op(self.int(lhs), self.double(rhs)), self.double(result)
|
|
|
|
)
|
|
|
|
self.assertIdentical(op(self.double(lhs), float(rhs)), self.double(result))
|
|
|
|
self.assertIdentical(op(float(lhs), self.double(rhs)), self.double(result))
|
|
|
|
self.assertIdentical(op(float(lhs), self.int(rhs)), self.double(result))
|
|
|
|
self.assertIdentical(op(self.int(lhs), float(rhs)), self.double(result))
|
|
|
|
|
|
|
|
def _test_shift(self, op, lhs, rhs, result):
|
|
|
|
self.assertIdentical(op(self.int(lhs), self.int(rhs)), self.int(result))
|
|
|
|
self.assertIdentical(op(self.int(lhs), self.long(rhs)), self.int(result))
|
|
|
|
self.assertIdentical(op(self.long(lhs), self.int(rhs)), self.long(result))
|
|
|
|
self.assertIdentical(op(self.long(lhs), self.long(rhs)), self.long(result))
|
|
|
|
self.assertIdentical(op(self.int(lhs), rhs), self.int(result))
|
|
|
|
self.assertIdentical(op(self.long(lhs), rhs), self.long(result))
|
|
|
|
self.assertIdentical(op(lhs, self.int(rhs)), self.int(result))
|
|
|
|
self.assertIdentical(op(lhs, self.long(rhs)), self.int(result))
|
|
|
|
|
|
|
|
self._test_pointer_type_errors(op)
|
|
|
|
self._test_floating_type_errors(op)
|
|
|
|
|
|
|
|
def _test_pointer_type_errors(self, op):
|
|
|
|
def pointer(value):
|
|
|
|
return Object(self.prog, "int *", value=value)
|
|
|
|
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError, "invalid operands to binary", op, self.int(1), pointer(1)
|
|
|
|
)
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError, "invalid operands to binary", op, pointer(1), self.int(1)
|
|
|
|
)
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError, "invalid operands to binary", op, pointer(1), pointer(1)
|
|
|
|
)
|
|
|
|
|
|
|
|
def _test_floating_type_errors(self, op):
|
|
|
|
self.assertRaises(TypeError, op, self.int(1), self.double(1))
|
|
|
|
self.assertRaises(TypeError, op, self.double(1), self.int(1))
|
|
|
|
self.assertRaises(TypeError, op, self.double(1), self.double(1))
|
|
|
|
|
|
|
|
def test_relational(self):
|
|
|
|
one = self.int(1)
|
|
|
|
two = self.int(2)
|
|
|
|
three = self.int(3)
|
|
|
|
|
|
|
|
self.assertTrue(one < two)
|
|
|
|
self.assertFalse(two < two)
|
|
|
|
self.assertFalse(three < two)
|
|
|
|
|
|
|
|
self.assertTrue(one <= two)
|
|
|
|
self.assertTrue(two <= two)
|
|
|
|
self.assertFalse(three <= two)
|
|
|
|
|
|
|
|
self.assertTrue(one == one)
|
|
|
|
self.assertFalse(one == two)
|
|
|
|
|
|
|
|
self.assertFalse(one != one)
|
|
|
|
self.assertTrue(one != two)
|
|
|
|
|
|
|
|
self.assertFalse(one > two)
|
|
|
|
self.assertFalse(two > two)
|
|
|
|
self.assertTrue(three > two)
|
|
|
|
|
|
|
|
self.assertFalse(one >= two)
|
|
|
|
self.assertTrue(two >= two)
|
|
|
|
self.assertTrue(three >= two)
|
|
|
|
|
|
|
|
# The usual arithmetic conversions convert -1 to an unsigned int.
|
|
|
|
self.assertFalse(self.int(-1) < self.unsigned_int(0))
|
|
|
|
|
|
|
|
self.assertTrue(self.int(1) == self.bool(1))
|
|
|
|
|
|
|
|
def test_ptr_relational(self):
|
|
|
|
ptr0 = Object(self.prog, "int *", value=0xFFFF0000)
|
|
|
|
ptr1 = Object(self.prog, "int *", value=0xFFFF0004)
|
|
|
|
fptr1 = Object(self.prog, "float *", value=0xFFFF0004)
|
|
|
|
|
|
|
|
self.assertTrue(ptr0 < ptr1)
|
|
|
|
self.assertTrue(ptr0 < fptr1)
|
|
|
|
self.assertFalse(ptr1 < fptr1)
|
|
|
|
|
|
|
|
self.assertTrue(ptr0 <= ptr1)
|
|
|
|
self.assertTrue(ptr0 <= fptr1)
|
|
|
|
self.assertTrue(ptr1 <= fptr1)
|
|
|
|
|
|
|
|
self.assertFalse(ptr0 == ptr1)
|
|
|
|
self.assertFalse(ptr0 == fptr1)
|
|
|
|
self.assertTrue(ptr1 == fptr1)
|
|
|
|
|
|
|
|
self.assertTrue(ptr0 != ptr1)
|
|
|
|
self.assertTrue(ptr0 != fptr1)
|
|
|
|
self.assertFalse(ptr1 != fptr1)
|
|
|
|
|
|
|
|
self.assertFalse(ptr0 > ptr1)
|
|
|
|
self.assertFalse(ptr0 > fptr1)
|
|
|
|
self.assertFalse(ptr1 > fptr1)
|
|
|
|
|
|
|
|
self.assertFalse(ptr0 >= ptr1)
|
|
|
|
self.assertFalse(ptr0 >= fptr1)
|
|
|
|
self.assertTrue(ptr1 >= fptr1)
|
|
|
|
|
|
|
|
self.assertRaises(TypeError, operator.lt, ptr0, self.int(1))
|
|
|
|
|
|
|
|
func = Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.function_type(self.prog.void_type(), (), False),
|
|
|
|
address=0xFFFF0000,
|
|
|
|
)
|
|
|
|
self.assertTrue(func == func)
|
|
|
|
self.assertTrue(func == ptr0)
|
|
|
|
|
|
|
|
array = Object(self.prog, "int [8]", address=0xFFFF0000)
|
|
|
|
self.assertTrue(array == array)
|
|
|
|
self.assertTrue(array != ptr1)
|
|
|
|
|
|
|
|
incomplete = Object(self.prog, "int []", address=0xFFFF0000)
|
|
|
|
self.assertTrue(incomplete == incomplete)
|
|
|
|
self.assertTrue(incomplete == ptr0)
|
|
|
|
|
|
|
|
self.assertRaises(
|
|
|
|
TypeError,
|
|
|
|
operator.eq,
|
|
|
|
Object(
|
|
|
|
self.prog, self.prog.struct_type("foo", None, None), address=0xFFFF0000
|
|
|
|
),
|
|
|
|
ptr0,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_add(self):
|
|
|
|
self._test_arithmetic(operator.add, 1, 2, 3, floating_point=True)
|
|
|
|
|
|
|
|
ptr = Object(self.prog, "int *", value=0xFFFF0000)
|
|
|
|
arr = Object(self.prog, "int [2]", address=0xFFFF0000)
|
|
|
|
ptr1 = Object(self.prog, "int *", value=0xFFFF0004)
|
|
|
|
self.assertIdentical(ptr + self.int(1), ptr1)
|
|
|
|
self.assertIdentical(self.unsigned_int(1) + ptr, ptr1)
|
|
|
|
self.assertIdentical(arr + self.int(1), ptr1)
|
|
|
|
self.assertIdentical(ptr1 + self.int(-1), ptr)
|
|
|
|
self.assertIdentical(self.int(-1) + ptr1, ptr)
|
|
|
|
|
|
|
|
self.assertIdentical(ptr + 1, ptr1)
|
|
|
|
self.assertIdentical(1 + ptr, ptr1)
|
|
|
|
self.assertRaises(TypeError, operator.add, ptr, ptr)
|
|
|
|
self.assertRaises(TypeError, operator.add, ptr, 2.0)
|
|
|
|
self.assertRaises(TypeError, operator.add, 2.0, ptr)
|
|
|
|
|
|
|
|
void_ptr = Object(self.prog, "void *", value=0xFFFF0000)
|
|
|
|
void_ptr1 = Object(self.prog, "void *", value=0xFFFF0001)
|
|
|
|
self.assertIdentical(void_ptr + self.int(1), void_ptr1)
|
|
|
|
self.assertIdentical(self.unsigned_int(1) + void_ptr, void_ptr1)
|
|
|
|
self.assertIdentical(void_ptr + 1, void_ptr1)
|
|
|
|
self.assertIdentical(1 + void_ptr, void_ptr1)
|
|
|
|
|
|
|
|
def test_sub(self):
|
|
|
|
self._test_arithmetic(operator.sub, 4, 2, 2, floating_point=True)
|
|
|
|
|
|
|
|
ptr = Object(self.prog, "int *", value=0xFFFF0000)
|
|
|
|
arr = Object(self.prog, "int [2]", address=0xFFFF0004)
|
|
|
|
ptr1 = Object(self.prog, "int *", value=0xFFFF0004)
|
|
|
|
self.assertIdentical(ptr1 - ptr, Object(self.prog, "ptrdiff_t", value=1))
|
|
|
|
self.assertIdentical(ptr - ptr1, Object(self.prog, "ptrdiff_t", value=-1))
|
|
|
|
self.assertIdentical(ptr - self.int(0), ptr)
|
|
|
|
self.assertIdentical(ptr1 - self.int(1), ptr)
|
|
|
|
self.assertIdentical(arr - self.int(1), ptr)
|
|
|
|
self.assertRaises(TypeError, operator.sub, self.int(1), ptr)
|
|
|
|
self.assertRaises(TypeError, operator.sub, ptr, 1.0)
|
|
|
|
|
|
|
|
void_ptr = Object(self.prog, "void *", value=0xFFFF0000)
|
|
|
|
void_ptr1 = Object(self.prog, "void *", value=0xFFFF0001)
|
|
|
|
self.assertIdentical(
|
|
|
|
void_ptr1 - void_ptr, Object(self.prog, "ptrdiff_t", value=1)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
void_ptr - void_ptr1, Object(self.prog, "ptrdiff_t", value=-1)
|
|
|
|
)
|
|
|
|
self.assertIdentical(void_ptr - self.int(0), void_ptr)
|
|
|
|
self.assertIdentical(void_ptr1 - self.int(1), void_ptr)
|
|
|
|
|
|
|
|
def test_mul(self):
|
|
|
|
self._test_arithmetic(operator.mul, 2, 3, 6, floating_point=True)
|
|
|
|
self._test_pointer_type_errors(operator.mul)
|
|
|
|
|
|
|
|
# Negative numbers.
|
|
|
|
self.assertIdentical(self.int(2) * self.int(-3), self.int(-6))
|
|
|
|
self.assertIdentical(self.int(-2) * self.int(3), self.int(-6))
|
|
|
|
self.assertIdentical(self.int(-2) * self.int(-3), self.int(6))
|
|
|
|
|
|
|
|
# Integer overflow.
|
2022-02-12 21:48:49 +00:00
|
|
|
self.assertIdentical(self.int(0x8000) * self.int(0x10000), self.int(-(2**31)))
|
2021-02-22 00:11:19 +00:00
|
|
|
|
|
|
|
self.assertIdentical(
|
2022-02-12 21:48:49 +00:00
|
|
|
self.unsigned_int(0x8000) * self.int(0x10000), self.unsigned_int(2**31)
|
2021-02-22 00:11:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
self.unsigned_int(0xFFFFFFFF) * self.unsigned_int(0xFFFFFFFF),
|
|
|
|
self.unsigned_int(1),
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
self.unsigned_int(0xFFFFFFFF) * self.int(-1), self.unsigned_int(1)
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_div(self):
|
|
|
|
self._test_arithmetic(operator.truediv, 6, 3, 2, floating_point=True)
|
|
|
|
|
|
|
|
# Make sure we do integer division for integer operands.
|
|
|
|
self._test_arithmetic(operator.truediv, 3, 2, 1)
|
|
|
|
|
|
|
|
# Make sure we truncate towards zero (Python truncates towards negative
|
|
|
|
# infinity).
|
|
|
|
self._test_arithmetic(operator.truediv, -1, 2, 0)
|
|
|
|
self._test_arithmetic(operator.truediv, 1, -2, 0)
|
|
|
|
|
|
|
|
self.assertRaises(ZeroDivisionError, operator.truediv, self.int(1), self.int(0))
|
|
|
|
self.assertRaises(
|
|
|
|
ZeroDivisionError,
|
|
|
|
operator.truediv,
|
|
|
|
self.unsigned_int(1),
|
|
|
|
self.unsigned_int(0),
|
|
|
|
)
|
|
|
|
self.assertRaises(
|
|
|
|
ZeroDivisionError, operator.truediv, self.double(1), self.double(0)
|
|
|
|
)
|
|
|
|
|
|
|
|
self._test_pointer_type_errors(operator.truediv)
|
|
|
|
|
|
|
|
def test_mod(self):
|
|
|
|
self._test_arithmetic(operator.mod, 4, 2, 0)
|
|
|
|
|
|
|
|
# Make sure the modulo result has the sign of the dividend (Python uses
|
|
|
|
# the sign of the divisor).
|
|
|
|
self._test_arithmetic(operator.mod, 1, 26, 1)
|
|
|
|
self._test_arithmetic(operator.mod, 1, -26, 1)
|
|
|
|
self._test_arithmetic(operator.mod, -1, 26, -1)
|
|
|
|
self._test_arithmetic(operator.mod, -1, -26, -1)
|
|
|
|
|
|
|
|
self.assertRaises(ZeroDivisionError, operator.mod, self.int(1), self.int(0))
|
|
|
|
self.assertRaises(
|
|
|
|
ZeroDivisionError, operator.mod, self.unsigned_int(1), self.unsigned_int(0)
|
|
|
|
)
|
|
|
|
|
|
|
|
self._test_pointer_type_errors(operator.mod)
|
|
|
|
self._test_floating_type_errors(operator.mod)
|
|
|
|
|
|
|
|
def test_lshift(self):
|
|
|
|
self._test_shift(operator.lshift, 2, 3, 16)
|
|
|
|
self.assertIdentical(self.bool(True) << self.bool(True), self.int(2))
|
|
|
|
self.assertIdentical(self.int(1) << self.int(32), self.int(0))
|
|
|
|
|
|
|
|
def test_rshift(self):
|
|
|
|
self._test_shift(operator.rshift, 16, 3, 2)
|
|
|
|
self.assertIdentical(self.int(-2) >> self.int(1), self.int(-1))
|
|
|
|
self.assertIdentical(self.int(1) >> self.int(32), self.int(0))
|
|
|
|
self.assertIdentical(self.int(-1) >> self.int(32), self.int(-1))
|
|
|
|
|
|
|
|
def test_and(self):
|
|
|
|
self._test_arithmetic(operator.and_, 1, 3, 1)
|
2022-02-12 21:48:49 +00:00
|
|
|
self.assertIdentical(self.int(-1) & self.int(2**31), self.int(2**31))
|
2021-02-22 00:11:19 +00:00
|
|
|
self._test_pointer_type_errors(operator.and_)
|
|
|
|
self._test_floating_type_errors(operator.and_)
|
|
|
|
|
|
|
|
def test_xor(self):
|
|
|
|
self._test_arithmetic(operator.xor, 1, 3, 2)
|
2022-02-12 21:48:49 +00:00
|
|
|
self.assertIdentical(self.int(-1) ^ self.int(-(2**31)), self.int(2**31 - 1))
|
2021-02-22 00:11:19 +00:00
|
|
|
self._test_pointer_type_errors(operator.xor)
|
|
|
|
self._test_floating_type_errors(operator.xor)
|
|
|
|
|
|
|
|
def test_or(self):
|
|
|
|
self._test_arithmetic(operator.or_, 1, 3, 3)
|
2022-02-12 21:48:49 +00:00
|
|
|
self.assertIdentical(self.int(-(2**31)) | self.int(2**31 - 1), self.int(-1))
|
2021-02-22 00:11:19 +00:00
|
|
|
self._test_pointer_type_errors(operator.or_)
|
|
|
|
self._test_floating_type_errors(operator.or_)
|
|
|
|
|
|
|
|
def test_pos(self):
|
|
|
|
# TestIntegerPromotion covers the other cases.
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError,
|
|
|
|
r"invalid operand to unary \+",
|
|
|
|
operator.pos,
|
|
|
|
Object(self.prog, "int *", value=0),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_neg(self):
|
|
|
|
self.assertIdentical(-Object(self.prog, "unsigned char", value=1), self.int(-1))
|
|
|
|
self.assertIdentical(-self.int(-1), self.int(1))
|
|
|
|
self.assertIdentical(-self.unsigned_int(1), self.unsigned_int(0xFFFFFFFF))
|
|
|
|
self.assertIdentical(
|
|
|
|
-Object(self.prog, "long", value=-0x8000000000000000),
|
|
|
|
Object(self.prog, "long", value=-0x8000000000000000),
|
|
|
|
)
|
|
|
|
self.assertIdentical(-self.double(2.0), self.double(-2.0))
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError,
|
|
|
|
"invalid operand to unary -",
|
|
|
|
operator.neg,
|
|
|
|
Object(self.prog, "int *", value=0),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_not(self):
|
|
|
|
self.assertIdentical(~self.int(1), self.int(-2))
|
|
|
|
self.assertIdentical(
|
|
|
|
~Object(self.prog, "unsigned long long", value=-1),
|
|
|
|
Object(self.prog, "unsigned long long", value=0),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
~Object(self.prog, "unsigned char", value=255), self.int(-256)
|
|
|
|
)
|
|
|
|
for type_ in ["int *", "double"]:
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError,
|
|
|
|
"invalid operand to unary ~",
|
|
|
|
operator.invert,
|
|
|
|
Object(self.prog, type_, value=0),
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_container_of(self):
|
|
|
|
obj = Object(self.prog, "int *", value=0xFFFF000C)
|
|
|
|
container_of(obj, self.point_type, "x")
|
|
|
|
self.assertIdentical(
|
|
|
|
container_of(obj, self.point_type, "x"),
|
|
|
|
Object(
|
|
|
|
self.prog, self.prog.pointer_type(self.point_type), value=0xFFFF000C
|
|
|
|
),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
container_of(obj, self.point_type, "y"),
|
|
|
|
Object(
|
|
|
|
self.prog, self.prog.pointer_type(self.point_type), value=0xFFFF0008
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertIdentical(
|
|
|
|
container_of(obj, self.line_segment_type, "a.x"),
|
|
|
|
Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.pointer_type(self.line_segment_type),
|
|
|
|
value=0xFFFF000C,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
container_of(obj, self.line_segment_type, "b.x"),
|
|
|
|
Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.pointer_type(self.line_segment_type),
|
|
|
|
value=0xFFFF0004,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
LookupError,
|
|
|
|
"'struct line_segment' has no member 'c'",
|
|
|
|
container_of,
|
|
|
|
obj,
|
|
|
|
self.line_segment_type,
|
|
|
|
"c.x",
|
|
|
|
)
|
|
|
|
|
|
|
|
polygon_type = self.prog.struct_type(
|
|
|
|
"polygon", 0, (TypeMember(self.prog.array_type(self.point_type), "points"),)
|
|
|
|
)
|
|
|
|
self.assertIdentical(
|
|
|
|
container_of(obj, polygon_type, "points[3].x"),
|
|
|
|
Object(self.prog, self.prog.pointer_type(polygon_type), value=0xFFFEFFF4),
|
|
|
|
)
|
|
|
|
|
|
|
|
small_point_type = self.prog.struct_type(
|
|
|
|
"small_point",
|
|
|
|
1,
|
|
|
|
(
|
|
|
|
TypeMember(
|
|
|
|
Object(
|
|
|
|
self.prog, self.prog.int_type("int", 4, True), bit_field_size=4
|
|
|
|
),
|
|
|
|
"x",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
TypeMember(
|
|
|
|
Object(
|
|
|
|
self.prog, self.prog.int_type("int", 4, True), bit_field_size=4
|
|
|
|
),
|
|
|
|
"y",
|
|
|
|
4,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
ValueError,
|
|
|
|
"member is not byte-aligned",
|
|
|
|
container_of,
|
|
|
|
obj,
|
|
|
|
small_point_type,
|
|
|
|
"y",
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError,
|
|
|
|
r"container_of\(\) argument must be a pointer",
|
|
|
|
container_of,
|
|
|
|
obj[0],
|
|
|
|
self.point_type,
|
|
|
|
"x",
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
TypeError,
|
|
|
|
"not a structure, union, or class",
|
|
|
|
container_of,
|
|
|
|
obj,
|
|
|
|
obj.type_,
|
|
|
|
"x",
|
|
|
|
),
|
|
|
|
|
|
|
|
type_ = self.prog.struct_type(
|
|
|
|
"foo",
|
|
|
|
16,
|
|
|
|
(
|
|
|
|
TypeMember(
|
|
|
|
self.prog.array_type(self.prog.int_type("int", 4, True), 8), "arr"
|
|
|
|
),
|
|
|
|
TypeMember(self.point_type, "point", 256),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
syntax_errors = [
|
|
|
|
("", r"^expected identifier$"),
|
|
|
|
("[1]", r"^expected identifier$"),
|
|
|
|
("point.", r"^expected identifier after '\.'$"),
|
|
|
|
("point(", r"^expected '\.' or '\[' after identifier$"),
|
|
|
|
("arr[1](", r"^expected '\.' or '\[' after ']'$"),
|
|
|
|
("arr[]", r"^expected number after '\['$"),
|
|
|
|
("arr[1)", r"^expected ']' after number$"),
|
|
|
|
]
|
|
|
|
for member_designator, error in syntax_errors:
|
|
|
|
self.assertRaisesRegex(
|
|
|
|
SyntaxError, error, container_of, obj, type_, member_designator
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class TestPrettyPrintObject(MockProgramTestCase):
|
|
|
|
def test_int(self):
|
|
|
|
obj = Object(self.prog, "int", value=99)
|
|
|
|
self.assertEqual(str(obj), "(int)99")
|
|
|
|
self.assertEqual(obj.format_(type_name=False), "99")
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "const int", value=-99)), "(const int)-99"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_char(self):
|
|
|
|
obj = Object(self.prog, "char", value=65)
|
|
|
|
self.assertEqual(str(obj), "(char)65")
|
|
|
|
self.assertEqual(obj.format_(char=True), "(char)'A'")
|
|
|
|
self.assertEqual(
|
|
|
|
Object(self.prog, "signed char", value=65).format_(char=True),
|
|
|
|
"(signed char)'A'",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
Object(self.prog, "unsigned char", value=65).format_(char=True),
|
|
|
|
"(unsigned char)'A'",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.typedef_type("uint8_t", self.prog.type("unsigned char")),
|
|
|
|
value=65,
|
|
|
|
).format_(char=True),
|
|
|
|
"(uint8_t)65",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_bool(self):
|
|
|
|
self.assertEqual(str(Object(self.prog, "_Bool", value=False)), "(_Bool)0")
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "const _Bool", value=True)), "(const _Bool)1"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_float(self):
|
|
|
|
self.assertEqual(str(Object(self.prog, "double", value=2.0)), "(double)2.0")
|
|
|
|
self.assertEqual(str(Object(self.prog, "float", value=0.5)), "(float)0.5")
|
|
|
|
|
|
|
|
def test_typedef(self):
|
|
|
|
type_ = self.prog.typedef_type("INT", self.prog.int_type("int", 4, True))
|
|
|
|
self.assertEqual(str(Object(self.prog, type_, value=99)), "(INT)99")
|
|
|
|
|
|
|
|
type_ = self.prog.typedef_type(
|
|
|
|
"INT", self.prog.int_type("int", 4, True), qualifiers=Qualifiers.CONST
|
|
|
|
)
|
|
|
|
self.assertEqual(str(Object(self.prog, type_, value=99)), "(const INT)99")
|
|
|
|
|
|
|
|
type_ = self.prog.typedef_type(
|
|
|
|
"CINT", self.prog.int_type("int", 4, True, qualifiers=Qualifiers.CONST)
|
|
|
|
)
|
|
|
|
self.assertEqual(str(Object(self.prog, type_, value=99)), "(CINT)99")
|
|
|
|
|
|
|
|
def test_struct(self):
|
|
|
|
segment = (
|
|
|
|
(99).to_bytes(4, "little")
|
|
|
|
+ (-1).to_bytes(4, "little", signed=True)
|
|
|
|
+ (12345).to_bytes(4, "little", signed=True)
|
|
|
|
+ (0).to_bytes(4, "little", signed=True)
|
|
|
|
)
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
self.types.append(self.point_type)
|
|
|
|
|
|
|
|
obj = Object(self.prog, "struct point", address=0xFFFF0000)
|
|
|
|
self.assertEqual(
|
|
|
|
str(obj),
|
|
|
|
"""\
|
|
|
|
(struct point){
|
|
|
|
.x = (int)99,
|
|
|
|
.y = (int)-1,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(member_type_names=False),
|
|
|
|
"""\
|
|
|
|
(struct point){
|
|
|
|
.x = 99,
|
|
|
|
.y = -1,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(members_same_line=True),
|
|
|
|
"(struct point){ .x = (int)99, .y = (int)-1 }",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(member_names=False),
|
|
|
|
"""\
|
|
|
|
(struct point){
|
|
|
|
(int)99,
|
|
|
|
(int)-1,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(members_same_line=True, member_names=False),
|
|
|
|
"(struct point){ (int)99, (int)-1 }",
|
|
|
|
)
|
|
|
|
|
|
|
|
type_ = self.prog.struct_type(
|
|
|
|
"foo",
|
|
|
|
16,
|
|
|
|
(
|
|
|
|
TypeMember(self.point_type, "point"),
|
|
|
|
TypeMember(
|
|
|
|
self.prog.struct_type(
|
|
|
|
None,
|
|
|
|
8,
|
|
|
|
(
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "bar"),
|
|
|
|
TypeMember(self.prog.int_type("int", 4, True), "baz", 32),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
None,
|
|
|
|
64,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
obj = Object(self.prog, type_, address=0xFFFF0000)
|
|
|
|
expected = """\
|
|
|
|
(struct foo){
|
|
|
|
.point = (struct point){
|
|
|
|
.x = (int)99,
|
|
|
|
.y = (int)-1,
|
|
|
|
},
|
|
|
|
.bar = (int)12345,
|
|
|
|
.baz = (int)0,
|
|
|
|
}"""
|
|
|
|
self.assertEqual(str(obj), expected)
|
|
|
|
self.assertEqual(str(obj.read_()), expected)
|
|
|
|
|
|
|
|
self.add_memory_segment(
|
|
|
|
(
|
|
|
|
(99).to_bytes(8, "little")
|
|
|
|
+ (-1).to_bytes(8, "little", signed=True)
|
|
|
|
+ (12345).to_bytes(8, "little", signed=True)
|
|
|
|
+ (0).to_bytes(8, "little", signed=True)
|
|
|
|
),
|
|
|
|
virt_addr=0xFFFF8000,
|
|
|
|
)
|
|
|
|
|
|
|
|
type_ = self.prog.struct_type(
|
|
|
|
"foo",
|
|
|
|
32,
|
|
|
|
(
|
|
|
|
TypeMember(
|
|
|
|
self.prog.struct_type(
|
|
|
|
"long_point",
|
|
|
|
16,
|
|
|
|
(
|
|
|
|
TypeMember(self.prog.int_type("long", 8, True), "x"),
|
|
|
|
TypeMember(self.prog.int_type("long", 8, True), "y", 64),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
"point",
|
|
|
|
),
|
|
|
|
TypeMember(self.prog.int_type("long", 8, True), "bar", 128),
|
|
|
|
TypeMember(self.prog.int_type("long", 8, True), "baz", 192),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
obj = Object(self.prog, type_, address=0xFFFF8000)
|
|
|
|
expected = """\
|
|
|
|
(struct foo){
|
|
|
|
.point = (struct long_point){
|
|
|
|
.x = (long)99,
|
|
|
|
.y = (long)-1,
|
|
|
|
},
|
|
|
|
.bar = (long)12345,
|
|
|
|
.baz = (long)0,
|
|
|
|
}"""
|
|
|
|
self.assertEqual(str(obj), expected)
|
|
|
|
self.assertEqual(str(obj.read_()), expected)
|
|
|
|
|
|
|
|
type_ = self.prog.struct_type("foo", 0, ())
|
|
|
|
self.assertEqual(str(Object(self.prog, type_, address=0)), "(struct foo){}")
|
|
|
|
|
|
|
|
obj = Object(self.prog, self.point_type, value={"x": 1})
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(implicit_members=False),
|
|
|
|
"""\
|
|
|
|
(struct point){
|
|
|
|
.x = (int)1,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(member_names=False, implicit_members=False),
|
|
|
|
"""\
|
|
|
|
(struct point){
|
|
|
|
(int)1,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
obj = Object(self.prog, self.point_type, value={"y": 1})
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(implicit_members=False),
|
|
|
|
"""\
|
|
|
|
(struct point){
|
|
|
|
.y = (int)1,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(member_names=False, implicit_members=False),
|
|
|
|
"""\
|
|
|
|
(struct point){
|
|
|
|
(int)0,
|
|
|
|
(int)1,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_bit_field(self):
|
|
|
|
self.add_memory_segment(b"\x07\x10\x5e\x5f\x1f\0\0\0", virt_addr=0xFFFF0000)
|
|
|
|
type_ = self.prog.struct_type(
|
|
|
|
"bits",
|
|
|
|
8,
|
|
|
|
(
|
|
|
|
TypeMember(
|
|
|
|
Object(
|
|
|
|
self.prog, self.prog.int_type("int", 4, True), bit_field_size=4
|
|
|
|
),
|
|
|
|
"x",
|
|
|
|
0,
|
|
|
|
),
|
|
|
|
TypeMember(
|
|
|
|
Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.int_type("int", 4, True, qualifiers=Qualifiers.CONST),
|
|
|
|
bit_field_size=28,
|
|
|
|
),
|
|
|
|
"y",
|
|
|
|
4,
|
|
|
|
),
|
|
|
|
TypeMember(
|
|
|
|
Object(
|
|
|
|
self.prog, self.prog.int_type("int", 4, True), bit_field_size=5
|
|
|
|
),
|
|
|
|
"z",
|
|
|
|
32,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
obj = Object(self.prog, type_, address=0xFFFF0000)
|
|
|
|
self.assertEqual(
|
|
|
|
str(obj),
|
|
|
|
"""\
|
|
|
|
(struct bits){
|
|
|
|
.x = (int)7,
|
|
|
|
.y = (const int)100000000,
|
|
|
|
.z = (int)-1,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(str(obj.x), "(int)7")
|
|
|
|
self.assertEqual(str(obj.y), "(const int)100000000")
|
|
|
|
self.assertEqual(str(obj.z), "(int)-1")
|
|
|
|
|
|
|
|
def test_union(self):
|
|
|
|
self.add_memory_segment(b"\0\0\x80?", virt_addr=0xFFFF0000)
|
|
|
|
self.types.append(self.option_type)
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "union option", address=0xFFFF0000)),
|
|
|
|
"""\
|
|
|
|
(union option){
|
|
|
|
.i = (int)1065353216,
|
|
|
|
.f = (float)1.0,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_enum(self):
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, self.color_type, value=0)), "(enum color)RED"
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, self.color_type, value=1)), "(enum color)GREEN"
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, self.color_type, value=4)), "(enum color)4"
|
|
|
|
)
|
|
|
|
obj = Object(self.prog, self.prog.enum_type("color"), address=0)
|
|
|
|
self.assertRaisesRegex(TypeError, "cannot format incomplete enum", str, obj)
|
|
|
|
|
|
|
|
def test_pointer(self):
|
|
|
|
self.add_memory_segment((99).to_bytes(4, "little"), virt_addr=0xFFFF0000)
|
|
|
|
obj = Object(self.prog, "int *", value=0xFFFF0000)
|
|
|
|
self.assertEqual(str(obj), "*(int *)0xffff0000 = 99")
|
|
|
|
self.assertEqual(obj.format_(dereference=False), "(int *)0xffff0000")
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "int *", value=0x7FFFFFFF)), "(int *)0x7fffffff"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_void_pointer(self):
|
|
|
|
self.add_memory_segment((99).to_bytes(4, "little"), virt_addr=0xFFFF0000)
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "void *", value=0xFFFF0000)), "(void *)0xffff0000"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_pointer_typedef(self):
|
|
|
|
self.add_memory_segment(
|
|
|
|
(0xFFFF00F0).to_bytes(8, "little"), virt_addr=0xFFFF0000
|
|
|
|
)
|
|
|
|
type_ = self.prog.typedef_type(
|
|
|
|
"HANDLE",
|
|
|
|
self.prog.pointer_type(self.prog.pointer_type(self.prog.void_type())),
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, type_, value=0xFFFF0000)),
|
|
|
|
"*(HANDLE)0xffff0000 = 0xffff00f0",
|
|
|
|
)
|
|
|
|
|
|
|
|
# TODO: test symbolize.
|
|
|
|
|
|
|
|
def test_c_string(self):
|
|
|
|
self.add_memory_segment(b"hello\0", virt_addr=0xFFFF0000)
|
|
|
|
self.add_memory_segment(b"unterminated", virt_addr=0xFFFF0010)
|
|
|
|
self.add_memory_segment(b'"escape\tme\\\0', virt_addr=0xFFFF0020)
|
|
|
|
|
|
|
|
obj = Object(self.prog, "char *", value=0xFFFF0000)
|
|
|
|
self.assertEqual(str(obj), '(char *)0xffff0000 = "hello"')
|
|
|
|
self.assertEqual(obj.format_(string=False), "*(char *)0xffff0000 = 104")
|
|
|
|
self.assertEqual(str(Object(self.prog, "char *", value=0x0)), "(char *)0x0")
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "char *", value=0xFFFF0010)), "(char *)0xffff0010"
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "char *", value=0xFFFF0020)),
|
|
|
|
r'(char *)0xffff0020 = "\"escape\tme\\"',
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_basic_array(self):
|
|
|
|
segment = bytearray()
|
|
|
|
for i in range(5):
|
|
|
|
segment.extend(i.to_bytes(4, "little"))
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
obj = Object(self.prog, "int [5]", address=0xFFFF0000)
|
|
|
|
|
|
|
|
self.assertEqual(str(obj), "(int [5]){ 0, 1, 2, 3, 4 }")
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(type_name=False, element_type_names=True),
|
|
|
|
"{ (int)0, (int)1, (int)2, (int)3, (int)4 }",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(element_indices=True),
|
|
|
|
"(int [5]){ [1] = 1, [2] = 2, [3] = 3, [4] = 4 }",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(element_indices=True, implicit_elements=True),
|
|
|
|
"(int [5]){ [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4 }",
|
|
|
|
)
|
|
|
|
self.assertEqual(obj.format_(columns=27), str(obj))
|
|
|
|
|
|
|
|
for columns in range(22, 26):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [5]){
|
|
|
|
0, 1, 2, 3, 4,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
for columns in range(19, 22):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [5]){
|
|
|
|
0, 1, 2, 3,
|
|
|
|
4,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
for columns in range(16, 19):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [5]){
|
|
|
|
0, 1, 2,
|
|
|
|
3, 4,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
for columns in range(13, 16):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [5]){
|
|
|
|
0, 1,
|
|
|
|
2, 3,
|
|
|
|
4,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
for columns in range(13):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [5]){
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
2,
|
|
|
|
3,
|
|
|
|
4,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(elements_same_line=False),
|
|
|
|
"""\
|
|
|
|
(int [5]){
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
2,
|
|
|
|
3,
|
|
|
|
4,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_nested_array(self):
|
|
|
|
segment = bytearray()
|
|
|
|
for i in range(10):
|
|
|
|
segment.extend(i.to_bytes(4, "little"))
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
obj = Object(self.prog, "int [2][5]", address=0xFFFF0000)
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
str(obj), "(int [2][5]){ { 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 } }"
|
|
|
|
)
|
|
|
|
self.assertEqual(obj.format_(columns=52), str(obj))
|
|
|
|
for columns in range(45, 52):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [2][5]){
|
|
|
|
{ 0, 1, 2, 3, 4 }, { 5, 6, 7, 8, 9 },
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
for columns in range(26, 45):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [2][5]){
|
|
|
|
{ 0, 1, 2, 3, 4 },
|
|
|
|
{ 5, 6, 7, 8, 9 },
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
for columns in range(24, 26):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [2][5]){
|
|
|
|
{
|
|
|
|
0, 1, 2,
|
|
|
|
3, 4,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
5, 6, 7,
|
|
|
|
8, 9,
|
|
|
|
},
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
for columns in range(21, 24):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [2][5]){
|
|
|
|
{
|
|
|
|
0, 1,
|
|
|
|
2, 3,
|
|
|
|
4,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
5, 6,
|
|
|
|
7, 8,
|
|
|
|
9,
|
|
|
|
},
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
for columns in range(21):
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=columns),
|
|
|
|
"""\
|
|
|
|
(int [2][5]){
|
|
|
|
{
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
2,
|
|
|
|
3,
|
|
|
|
4,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
5,
|
|
|
|
6,
|
|
|
|
7,
|
|
|
|
8,
|
|
|
|
9,
|
|
|
|
},
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_array_member(self):
|
|
|
|
segment = bytearray()
|
|
|
|
for i in range(5):
|
|
|
|
segment.extend(i.to_bytes(4, "little"))
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
|
|
|
|
type_ = self.prog.struct_type(
|
|
|
|
None,
|
|
|
|
20,
|
|
|
|
(
|
|
|
|
TypeMember(
|
|
|
|
self.prog.array_type(self.prog.int_type("int", 4, True), 5), "arr"
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
obj = Object(self.prog, type_, address=0xFFFF0000)
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
str(obj),
|
|
|
|
"""\
|
|
|
|
(struct <anonymous>){
|
|
|
|
.arr = (int [5]){ 0, 1, 2, 3, 4 },
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
self.assertEqual(obj.format_(columns=42), str(obj))
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=41),
|
|
|
|
"""\
|
|
|
|
(struct <anonymous>){
|
|
|
|
.arr = (int [5]){
|
|
|
|
0, 1, 2, 3, 4,
|
|
|
|
},
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(columns=18),
|
|
|
|
"""\
|
|
|
|
(struct <anonymous>){
|
|
|
|
.arr = (int [5]){
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
2,
|
|
|
|
3,
|
|
|
|
4,
|
|
|
|
},
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_array_of_struct(self):
|
|
|
|
segment = bytearray()
|
|
|
|
for i in range(1, 5):
|
|
|
|
segment.extend(i.to_bytes(4, "little"))
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
self.types.append(self.point_type)
|
|
|
|
|
|
|
|
obj = Object(self.prog, "struct point [2]", address=0xFFFF0000)
|
|
|
|
self.assertEqual(
|
|
|
|
str(obj),
|
|
|
|
"""\
|
|
|
|
(struct point [2]){
|
|
|
|
{
|
|
|
|
.x = (int)1,
|
|
|
|
.y = (int)2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.x = (int)3,
|
|
|
|
.y = (int)4,
|
|
|
|
},
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_zero_length_array(self):
|
|
|
|
self.assertEqual(str(Object(self.prog, "int []", address=0)), "(int []){}")
|
|
|
|
self.assertEqual(str(Object(self.prog, "int [0]", address=0)), "(int [0]){}")
|
|
|
|
|
|
|
|
def test_array_zeroes(self):
|
|
|
|
segment = bytearray(16)
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
self.types.append(self.point_type)
|
|
|
|
self.types.append(self.prog.struct_type("empty", 0, ()))
|
|
|
|
|
|
|
|
obj = Object(self.prog, "int [2]", address=0xFFFF0000)
|
|
|
|
self.assertEqual(str(obj), "(int [2]){}")
|
|
|
|
self.assertEqual(obj.format_(implicit_elements=True), "(int [2]){ 0, 0 }")
|
|
|
|
segment[:4] = (99).to_bytes(4, "little")
|
|
|
|
self.assertEqual(str(obj), "(int [2]){ 99 }")
|
|
|
|
segment[:4] = (0).to_bytes(4, "little")
|
|
|
|
segment[4:8] = (99).to_bytes(4, "little")
|
|
|
|
self.assertEqual(str(obj), "(int [2]){ 0, 99 }")
|
|
|
|
|
|
|
|
obj = Object(self.prog, "struct point [2]", address=0xFFFF0000)
|
|
|
|
self.assertEqual(
|
|
|
|
str(obj),
|
|
|
|
"""\
|
|
|
|
(struct point [2]){
|
|
|
|
{
|
|
|
|
.x = (int)0,
|
|
|
|
.y = (int)99,
|
|
|
|
},
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
obj = Object(self.prog, "struct empty [2]", address=0)
|
|
|
|
self.assertEqual(str(obj), "(struct empty [2]){}")
|
|
|
|
|
|
|
|
def test_char_array(self):
|
|
|
|
segment = bytearray(16)
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
|
|
|
|
obj = Object(self.prog, "char [4]", address=0xFFFF0000)
|
|
|
|
segment[:16] = b"hello, world\0\0\0\0"
|
|
|
|
self.assertEqual(str(obj), '(char [4])"hell"')
|
|
|
|
self.assertEqual(obj.format_(string=False), "(char [4]){ 104, 101, 108, 108 }")
|
|
|
|
self.assertEqual(str(obj.read_()), str(obj))
|
|
|
|
segment[2] = 0
|
|
|
|
self.assertEqual(str(obj), '(char [4])"he"')
|
|
|
|
self.assertEqual(str(obj.read_()), str(obj))
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "char [0]", address=0xFFFF0000)), "(char [0]){}"
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, "char []", address=0xFFFF0000)), "(char []){}"
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_function(self):
|
|
|
|
obj = Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.function_type(self.prog.void_type(), (), False),
|
|
|
|
address=0xFFFF0000,
|
|
|
|
)
|
|
|
|
self.assertEqual(str(obj), "(void (void))0xffff0000")
|
|
|
|
|
|
|
|
def test_absent(self):
|
|
|
|
self.assertRaises(TypeError, str, Object(self.prog, "void"))
|
|
|
|
|
|
|
|
for type_ in [
|
|
|
|
"int",
|
|
|
|
"char",
|
|
|
|
"_Bool",
|
|
|
|
"double",
|
|
|
|
self.point_type,
|
|
|
|
self.option_type,
|
|
|
|
self.coord_type,
|
|
|
|
self.color_type,
|
|
|
|
"size_t",
|
|
|
|
"void *",
|
|
|
|
"int [2]",
|
|
|
|
self.prog.function_type(self.prog.void_type(), ()),
|
|
|
|
]:
|
|
|
|
if isinstance(type_, Type):
|
|
|
|
type_name = type_.type_name()
|
|
|
|
else:
|
|
|
|
type_name = type_
|
|
|
|
self.assertEqual(str(Object(self.prog, type_)), f"({type_name})<absent>")
|
libdrgn: support value objects with >64-bit integer types
The Linux kernel's struct task_struct on AArch64 contains an array of
__uint128_t:
>>> task = find_task(prog, 1)
>>> task.type_
struct task_struct *
>>> task.thread.type_
struct thread_struct {
struct cpu_context cpu_context;
struct {
unsigned long tp_value;
unsigned long tp2_value;
struct user_fpsimd_state fpsimd_state;
} uw;
enum fp_type fp_type;
unsigned int fpsimd_cpu;
void *sve_state;
void *sme_state;
unsigned int vl[2];
unsigned int vl_onexec[2];
unsigned long fault_address;
unsigned long fault_code;
struct debug_info debug;
struct ptrauth_keys_user keys_user;
struct ptrauth_keys_kernel keys_kernel;
u64 mte_ctrl;
u64 sctlr_user;
u64 svcr;
u64 tpidr2_el0;
}
>>> task.thread.uw.fpsimd_state.type_
struct user_fpsimd_state {
__int128 unsigned vregs[32];
__u32 fpsr;
__u32 fpcr;
__u32 __reserved[2];
}
As a result, printing a task_struct fails:
>>> task
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/host/home/osandov/repos/drgn3/drgn/cli.py", line 140, in _displayhook
text = value.format_(columns=shutil.get_terminal_size((0, 0)).columns)
NotImplementedError: integer values larger than 64 bits are not yet supported
PR #311 suggested treating >64-bit integers as byte arrays for now; I
tried an alternate hack of handling >64-bit integers only in the
pretty-printing code. Both of these had issues, though.
Instead, let's push >64-bit integer support a little further and allow
storing "big integer" value objects. We still don't support any
operations on them, so this still doesn't complete #170. We store the
raw bytes of the value for now, but we'll probably change this if we add
support for operations (e.g., to store the value as an mp_limb_t array
for GMP). We also print >64-bit integer types in hexadecimal for
simplicity. This is inconsistent with the existing behavior of printing
in decimal, but more readable. In the future, we might want to add
heuristics to decide when to print in decimal vs hexadecimal for all
sizes.
Closes #311.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-08-02 21:12:19 +01:00
|
|
|
|
|
|
|
def test_bigint(self):
|
|
|
|
segment = bytearray(16)
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
|
|
|
|
for byteorder in ("little", "big"):
|
|
|
|
with self.subTest(byteorder=byteorder):
|
|
|
|
obj = Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.int_type("unsigned __int128", 16, False, byteorder),
|
|
|
|
address=0xFFFF0000,
|
|
|
|
)
|
|
|
|
for value in (
|
|
|
|
0,
|
|
|
|
0x100,
|
|
|
|
0x112233445566778899AABBCCDDEEFF,
|
|
|
|
0xFEDCBA9876543210,
|
|
|
|
):
|
|
|
|
segment[:] = value.to_bytes(16, byteorder)
|
|
|
|
self.assertEqual(str(obj), "(unsigned __int128)" + hex(value))
|
|
|
|
|
|
|
|
def test_bigint_in_array(self):
|
|
|
|
segment = bytearray(16 * 3)
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
|
|
|
|
for byteorder in ("little", "big"):
|
|
|
|
with self.subTest(byteorder=byteorder):
|
|
|
|
segment[:16] = (0x112233445566778899AABBCCDDEEFF).to_bytes(
|
|
|
|
16, byteorder
|
|
|
|
)
|
|
|
|
segment[16:32] = (0xDEADBEEF).to_bytes(16, byteorder)
|
|
|
|
obj = Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.array_type(
|
|
|
|
self.prog.int_type("unsigned __int128", 16, False, byteorder), 3
|
|
|
|
),
|
|
|
|
address=0xFFFF0000,
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
str(obj),
|
|
|
|
"(unsigned __int128 [3]){ 0x112233445566778899aabbccddeeff, 0xdeadbeef }",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(implicit_elements=True),
|
|
|
|
"(unsigned __int128 [3]){ 0x112233445566778899aabbccddeeff, 0xdeadbeef, 0x0 }",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_bigint_in_struct(self):
|
|
|
|
segment = bytearray(16 * 3)
|
|
|
|
self.add_memory_segment(segment, virt_addr=0xFFFF0000)
|
|
|
|
|
|
|
|
for byteorder in ("little", "big"):
|
|
|
|
with self.subTest(byteorder=byteorder):
|
|
|
|
segment[:16] = (0x112233445566778899AABBCCDDEEFF).to_bytes(
|
|
|
|
16, byteorder
|
|
|
|
)
|
|
|
|
segment[16:32] = (0xDEADBEEF).to_bytes(16, byteorder)
|
|
|
|
type = self.prog.int_type("unsigned __int128", 16, False, byteorder)
|
|
|
|
obj = Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.struct_type(
|
|
|
|
"foo",
|
|
|
|
16 * 3,
|
|
|
|
(
|
|
|
|
TypeMember(type, "a"),
|
|
|
|
TypeMember(type, "b", 16 * 8),
|
|
|
|
TypeMember(type, "c", 16 * 8 * 2),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
address=0xFFFF0000,
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
str(obj),
|
|
|
|
"""\
|
|
|
|
(struct foo){
|
|
|
|
.a = (unsigned __int128)0x112233445566778899aabbccddeeff,
|
|
|
|
.b = (unsigned __int128)0xdeadbeef,
|
|
|
|
.c = (unsigned __int128)0x0,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
self.assertEqual(
|
|
|
|
obj.format_(implicit_members=False),
|
|
|
|
"""\
|
|
|
|
(struct foo){
|
|
|
|
.a = (unsigned __int128)0x112233445566778899aabbccddeeff,
|
|
|
|
.b = (unsigned __int128)0xdeadbeef,
|
|
|
|
}""",
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_bigint_typedef(self):
|
|
|
|
self.add_memory_segment(
|
|
|
|
(0xDEADBEEF).to_bytes(16, "little"), virt_addr=0xFFFF0000
|
|
|
|
)
|
|
|
|
type = self.prog.typedef_type(
|
|
|
|
"__uint128_t", self.prog.int_type("unsigned __int128", 16, False)
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, type, address=0xFFFF0000)),
|
|
|
|
"(__uint128_t)0xdeadbeef",
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
str(Object(self.prog, self.prog.array_type(type, 1), address=0xFFFF0000)),
|
|
|
|
"(__uint128_t [1]){ 0xdeadbeef }",
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
str(
|
|
|
|
Object(
|
|
|
|
self.prog,
|
|
|
|
self.prog.struct_type("foo", 16, (TypeMember(type, "a"),)),
|
|
|
|
address=0xFFFF0000,
|
|
|
|
)
|
|
|
|
),
|
|
|
|
"""\
|
|
|
|
(struct foo){
|
|
|
|
.a = (__uint128_t)0xdeadbeef,
|
|
|
|
}""",
|
|
|
|
)
|