Variable Length Arrays (VLA) proposal

Agovic, Sanimir
2013-06-28T13:03:47Z

Hello,

FSF GDB is currently not able to evaluate Variable Length Arrays (VLA) for
various languages e.g. Fortran and C. The root cause are dynamic values of
attributes like length and bounds of array types (see dwarf4:2.19).

On the archer project [1] VLA support was implemented by Jan Kratochvil and is
known to be shipped with Fedora. This implementation hooks into check_typedef
and resolves the dynamic values to existing static attributes. However, this
approach has some drawbacks, which are addressed in Jan's big plan for VLA [1].

We've created three proposals, how VLA support can be added to FSF GDB.

(1)
Resolving check_typedef:

This proposal is mainly based on Jan's proposal [2].

The function check_typedef does primary two things: it updates the passed type
structure in terms of dynamic attributes, e.g. the size, bounds, etc. and it
creates a deep copy of the passed type, completes it and returns it to the
caller. The function check_typedef will be called in the GDB code base before
attributes of the type structure will be accessed. This should guarantee that
the type is up-to-date. However, the GDB code base is known that this function
call is also missed in some places, which may result in flaky behavior. The type
evaluation may or may not work. As check_typedef is a big monolithic function it
should be split into smaller parts, which are responsible for very specific
tasks, e.g. calculating and updating the size of a type. By just splitting the
function into several parts will not solve the primary check_typedef problem.
To solve this, almost all TYPE_* macros, which access potential dynamic
attributes, need to be changed in order to call the respective functions to
calculate dynamic attributes instead of just accessing them statically. For
calculating sizes and bounds the inferior memory is required. Thus the parameter
of most of the TYPE_* macros need to be changed from "struct type*" to
"struct value*", as "struct value*" contains the memory of the inferior as well
as "struct type*". By changing the semantic of the TYPE_* macros, so called
writer macros need to be introduced as some TYPE_* macros occur on the left
side. E.g:
TYPE_LENGTH(type) = 1;
However, there is much risk for breaking things by changing most of the TYPE_*
macros in combination with splitting check_typedef. By going this way the GDB
mainline needs to be freezed at least for some days to get the changes into the
repository once they are ready to avoid ending up in a merging disaster. This is
because the changes are spread over the whole GDB source base.

(2)
Type normalization:

This proposal is similar to Jan's approach [1] in transforming dynamic values
of attributes into static ones:

1) resolve all dynamic attributes
2) create a copy of the type and assign the resolved attributes from step 1)

This proposal doesn't require to change check_typdef completely nor changing,
the TYPE_* macros, which makes this solution very isolated and lean.
Instead of hijacking check_typedef we hook into value_type() to normalize the
type. Since inferior types depend on a context - namely an address - to be
resolvable this seems a good place to hook into. In addition all expression
evaluations are routed via parse_and_eval() which returns a value, which may be
associated with an address. Also the TYPE_* macros in gdbtypes.h could be left
as-is. As a side effect gdb is now constantly creating types during the
normalization process and will increase the memory consumption constantly as
well. To avoid this behavior a garbage collector would be needed, which frees
the memory again when required. This could be done for example when GDB returns
to its main loop. Nevertheless, such a garbage collector can result in a
performance overhead, which is expected to be very small.

(3)
Split struct type:

The idea behind this proposal is to reflect the difference of types (dynamic/
static attributes) in the type system used in GDB. At the moment we consider the
following types:

- struct type
Serves as a base. Certain properties are exposed using function pointers
instead of raw attribute access e.g. length, bounds.

- struct static_type
Reassembles the functionality of the current struct type. It is used for
types with statically values of attributes.

- struct dynamic type
Allows to express the dynamic values of attributes. Computation of length
and bounds might be done lazily.

- struct typedef_type
A simple proxy type. Calls to length and bounds are forwarded to the
underlying type.

An implementation details which is left out is whether one would implement it in
a OO style similar to breakpoint_ops.

The main advantage is the increased maintainability of the type system itself as
there would be a clear differentiation between static and dynamic types. Also
extensions and future requirements could be better addressed by simply
refactoring struct members into function pointers. The check_type function could
be shortened, as function pointers will do the dynamic calculation work, and in
future steps completely removed by adding a function peel(), which would
recursively peel of any typedefs. This change would be rather large and would
affect many areas of GDB, like proposal (1).

Summary:
Proposal (1) would be very expensive and dangerous as the side effects of
resolving and removing check_typedef in one shot are not known. As a lot of
macros have to be changed as well, the whole GDB code base will be affected.
The implementation of proposal (2) would be very isolated and simple, but will
leave the static attributes in struct type, which are actually dynamic.
Proposal (3) will make the type system of GDB more flexible, as differentiating
between static and dynamic types. Also it will calculate dynamic attributes when
they will be requested by the caller. However, also this change will be large as
lots of GDB code need to be touched but it is the preferred proposal from our
side.

We would appreciate your feedback and thoughts about the different proposals.

-- Keven & Sanimir

[1] http://sourceware.org/gdb/wiki/ProjectArcher
(branch archer-jankratochvil-vla)
[2] http://sourceware.org/ml/gdb/2012-11/msg00094.html
Intel GmbH
Dornacher Strasse 1
85622 Feldkirchen/Muenchen, Deutschland
Sitz der Gesellschaft: Feldkirchen bei Muenchen
Geschaeftsfuehrer: Christian Lamprechter, Hannes Schwaderer, Douglas Lusk
Registergericht: Muenchen HRB 47456
Ust.-IdNr./VAT Registration No.: DE129385895
Citibank Frankfurt a.M. (BLZ 502 109 00) 600119052