Commit Graph

87 Commits

Author SHA1 Message Date
Omar Sandoval
4f56a22d2e dwarftypeindex: handle zero-length and flexible array ambiguity
The DIE generated by GCC for a zero-length array doesn't have a
DW_AT_upper_bound or DW_AT_count attribute; it looks identical to that
of a flexible array. See
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86985.

The semantics of zero-length and flexible arrays are slightly different
(see https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html), so there are
a few specific cases where replacing a zero-length array with a flexible
array creates an invalid type. We can tell when the type must have been
a zero-length array; in other cases, we will just assume the type is a
flexible array. This ambiguity will hopefully be fixed in a future
version of GCC.
2018-08-17 00:41:47 -07:00
Omar Sandoval
98a26ad610 corereader: add CoreReader.read_c_string()
And replace the Python implementation in ProgramObject.string_(). The
CoreReader implementation is still naive in that it reads byte-by-byte,
but this could always be improved in the future.
2018-07-23 18:19:41 -07:00
Omar Sandoval
b70addd5ae type: get rid of unused Type._read_pretty() 2018-07-22 00:30:41 -07:00
Omar Sandoval
cab896a65b type: exclude all-zero arrays and structs from array pretty-printing 2018-07-22 00:26:10 -07:00
Omar Sandoval
f4bb55e359 type: support putting multiple array elements on the same line 2018-07-21 22:53:05 -07:00
Omar Sandoval
6f14d82024 memberdesignator: fix error message when missing ']' 2018-07-16 20:30:09 -07:00
Omar Sandoval
0cb3876900 tests: don't shell out to GCC for DwarfTypeIndex tests
Instead, make a mock DwarfIndex and CompilationUnit and construct Dies
directly.
2018-07-16 19:45:30 -07:00
Omar Sandoval
a69a743f55 tests: fix const_anonymous_color_type
It has negative enumerators, so it obviously must be signed.
2018-07-16 19:42:52 -07:00
Omar Sandoval
45da5e8d35 tests: split DwarfTypeIndex tests out of TypeIndex tests 2018-07-15 18:07:36 -07:00
Omar Sandoval
878e4017c8 type: add new CompoundType.members()
CompoundType.members() currently returns a list of member names;
sometimes, we actually want the type and offset. So, rename members() to
member_names(), and make members() return the type and offset, using a
newly added version of functools.partial() that caches the return value.
2018-07-15 08:08:42 -07:00
Omar Sandoval
6abb2f2402 Separate internal API from public API
While we're here, clean up some rough edges of the API and document a
lot more.
2018-07-14 10:20:17 -07:00
Omar Sandoval
9273de829b type: handle anonymous types thoroughly
There were a couple more corner cases missing: arrays of anonymous types
and bit fields of anonymous enums.
2018-07-11 23:56:32 -07:00
Omar Sandoval
51aa35bc05 type: also format typedefs of anonymous enums 2018-07-11 22:34:01 -07:00
Omar Sandoval
6fa2d68c0c type: add Type.unqualified() 2018-07-11 21:51:48 -07:00
Omar Sandoval
9b5b721838 type: format typedefs of anonymous types better
Currently, printing, e.g.,

typedef struct {
	int counter;
} atomic_t

results in

typedef struct atomic_t

Which isn't very useful. Instead, print the former.
2018-07-11 21:40:01 -07:00
Omar Sandoval
6a6d37c5e1 Make Program and CoreReader context managers
This is preparation for the next change, so that a Program can clean up
after itself. The Program will close the CoreReader, and the CoreReader
will close the underlying file.
2018-07-11 19:16:34 -07:00
Omar Sandoval
800ee3ec36 corereader: take fd and list of segments instead of path
Now, we can get rid of the ELF parsing implementation in CoreReader.
Instead, we parse in ElfFile and pass the parsed information to
CoreReader.
2018-07-09 19:12:33 -07:00
Omar Sandoval
7ae295dda5 Add MemoryViewIO
This will be used so that ElfFile can take a BufferedIOReader instead of
a memoryview.
2018-07-09 17:03:15 -07:00
Omar Sandoval
306862167d corereader: handle segments with p_filesz < p_memsz
The extra is defined to be zero-filled.
2018-07-06 19:28:20 -07:00
Omar Sandoval
a22f4b7d4f corereader: save segments as Elf64_Phdr
This is preparation for the following two changes.
2018-07-06 18:01:57 -07:00
Omar Sandoval
50f52ec295 program: make ProgramObject() arguments mandatory keywords
It's too hard to remember whether value or address comes first, so make
sure we're always explicit which one.
2018-06-28 23:40:47 -07:00
Omar Sandoval
aeb767d43e Replace lookup_variable callback with new VariableIndex class
Similar to how we replaced the lookup_type callback with TypeIndex.
2018-06-28 21:05:21 -07:00
Omar Sandoval
02c75770ea typeindex: support disambiguating types by filename 2018-06-28 19:34:10 -07:00
Omar Sandoval
0adac0747c Bring back ElfFile
Instead of constructing DwarfFile with a dict of sections, pass in an
ElfFile.
2018-06-25 23:43:14 -07:00
Omar Sandoval
26d3880708 dwarfindex: move indexing to a method instead of __init__()
We want to allow indexing files on the fly instead of all up front, so
move the indexing to a new DwarfIndex.add() method.
2018-06-25 00:25:49 -07:00
Omar Sandoval
e2caf2bb0d dwarfindex: don't index any declarations and handle specifications
For variables which are predeclared, GCC generates a DW_TAG_variable DIE
with DW_AT_name and DW_AT_declaration as well as a DW_TAG_variable DIE
without DW_AT_name but with DW_AT_specification pointing to the
declaration DIE. We should index the latter, not the former. This has a
couple of benefits: we can skip indexing variable declaration DIEs,
which contribute a lot of duplicate hash table insertions; and, we can
always get the address of a variable from DW_AT_location of the indexed
DIE instead of having to parse the symbol table.
2018-06-23 00:23:30 -07:00
Omar Sandoval
5e2d70f09e dwarfindex: add file name to DIE index entry key
A name and tag are not always enough to uniquely identify a type or
variable. For example, "struct workspace" in the Linux kernel can refer
to one of at least three types; fs/btrfs/{lzo,zlib,zstd}.c each have
their own struct workspace type. We can, however, also differentiate
DIEs on the file they were declared in.

The naive thing to do would be to include the file name as a string in
the hash table entry. However, that means we must allocate and
canonicalize each path in the line number program header and pay an
extra cache miss plus string comparison when adding a new entry.

We can get rid of the cache miss and string comparison if we instead map
the file name to a unique identifier. The foolproof way to do this would
be to create another big hash table of file names and use the hash table
entry index as the unique identifier. However, for this, we'd still need
to allocate and canoicalize each path as well as worry about another big
hash table.

Once we observe that we can get away with "almost certainly unique"
instead of "truly unique" identifiers, the next logical step is to just
use a hash of the file name as the identifier. With a 64-bit hash and
the ~50k files in the kernel, the probability of a collision is 1 in 10
billion. Even in the extremely unlikely event that there is a collision,
it only matters if the files with colliding names also have colliding
DIEs, which brings things pretty close to the realm of impossibility.

After this change, DwarfIndex.find() returns a list of DIEs matching the
name and tag. The callers will be updated to use the list in upcoming
changes.
2018-06-21 23:13:39 -07:00
Omar Sandoval
856892375a typeindex: handle pointer to const void in from_dwarf_type()
Like pointer types and function types, qualified void types don't have a
DW_AT_type.
2018-06-15 22:36:58 -07:00
Omar Sandoval
2ee6662639 program: handle pointers to typedefs of struct/union types
ProgramObject.__dir__(), member_(), and container_of_() all check that
the relevant type is a struct or union, but they all need to allow
typedefs of structs or unions, as well.
2018-05-25 22:32:03 -07:00
Omar Sandoval
6b178c5108 program: only check struct or union in ProgramObject.member_()
We're currently also doing this check in __getattr__(), which is
unnecessary overhead in the common case. We can just check the exception
in the error case.
2018-05-25 21:56:24 -07:00
Omar Sandoval
95c0682718 corereader: implement type reads in C
Now that read_memory() was converted to C, IntType.read() and friends
are a bottleneck. Convert them to C methods of CoreReader.
2018-05-25 00:41:12 -07:00
Omar Sandoval
95bde56cb7 Implement core dump reading in C
read_memory() is one of the hottest functions in profiles of tight loops
over lists of items, and it can be done much more efficiently in C.
2018-05-24 17:55:47 -07:00
Omar Sandoval
15849f5795 type: make operand_type() a method of Type
This gets rid of the huge isinstance() chain in
TypeIndex.operand_type().
2018-05-18 23:51:20 -07:00
Omar Sandoval
e7a2ba32e8 program: show dereferenced value for ProgramObject.str()
I always forget to dereference pointers, which gets annoying.
2018-05-14 20:36:19 -07:00
Omar Sandoval
54f5124be8 type: format char arrays as strings
For, e.g., comm in struct task_struct, a string is much nicer to look
at.
2018-05-14 20:35:21 -07:00
Omar Sandoval
6d980a95a7 Add better rlcompleter
The standard library rlcompleter doesn't support expressions involving
an item lookup (e.g., x[0] or x['foo']). This is a pain for the drgn
CLI, because it's common to use prog['variable'] and want to
autocomplete it. Instead of using the standard library rlcompleter,
implement our own, cleaned up version of it with the ability to handle
expressions containing [key]. rlcompleter already allows for arbitrary
__getattr__() calls, and __getitem__() isn't any different.
2018-05-13 23:51:42 -07:00
Omar Sandoval
e327aef860 program: fix ProgramObject.__round__() with ndigits is not None
In this case, we must return a ProgramObject.
2018-05-13 00:47:44 -07:00
Omar Sandoval
1916528f5d type: make offsetof() and typeof() accept arbitrary member designators
Instead of only accepting an identifier.
2018-05-13 00:42:50 -07:00
Omar Sandoval
8f46673649 Add member designator parser
A member designator is the second argument to the C offsetof() macro.
2018-05-13 00:41:20 -07:00
Omar Sandoval
90ca412a33 typeindex: fix mypy errors in drgn.program 2018-05-12 15:34:00 -07:00
Omar Sandoval
f299bea98a type/typeindex: implement saner typing for EnumType
This is a big change that makes EnumType have a compatible integer type
member instead of copying the fields, which ends up touching a lot of
stuff but also fixing a bunch of static typing errors.
2018-05-11 23:57:52 -07:00
Omar Sandoval
35271231fe program: swap ProgramObject arguments
type, address, value makes more sense and looks more like C.
2018-05-07 22:48:00 -07:00
Omar Sandoval
15ea6e8d97 program: implement ProgramObject binary operators 2018-05-07 18:48:10 -07:00
Omar Sandoval
9560b913f3 typeindex: change Type.unqualified() to TypeIndex.operand_type()
Converting an lvalue to an operand has to do a little bit more than
remove qualifiers:

- Convert array types to pointer types
- Convert function types to pointer types
2018-05-06 21:29:59 -07:00
Omar Sandoval
987f9be6db type: add Type.is_arithmetic() and Type.is_integer()
This will be used for ProgramObject operators as a shortcut for
isinstance(type.real_type(), (ArithmeticType, BitFieldType).
2018-05-06 00:28:07 -07:00
Omar Sandoval
da83e0adb3 program: add ProgramObject tests 2018-05-03 23:26:43 -07:00
Omar Sandoval
38262f8d53 typeindex: add TypeIndex.pointer() 2018-05-03 22:34:35 -07:00
Omar Sandoval
18e5e8f9bf typeindex: move easy types into base TypeIndex class
Some types don't actually have to go through find_dwarf_type(), so they
can be handled in the common code. This allows us to add a MockTypeIndex
to the tests.
2018-05-03 20:38:00 -07:00
Omar Sandoval
3cc11f3f5e typeindex: rename usual_arithmetic_conversions() to common_real_type()
It doesn't actually do the conversion, it just finds the common type.
While we're here, don't make the types unqualied; the caller should do
that.
2018-05-02 23:36:39 -07:00
Omar Sandoval
928048be97 tests: use mocked TypeIndex for type conversion tests
Instead of a real DwarfTypeIndex.
2018-05-02 23:19:05 -07:00