Hi, Hui Zang,
It helps to remember that at runtime a variable of a structure type has to be allocated store, and to think about how that variable is laid out in store.
You must use createMemberType to create a DIType for each field (aka member) in the structure; you then store those DIType’s as the elements of a DIArray which you pass as the ‘Elements’ parameter to createStructType.
When creating a structure member, you have to specify this information :
SizeinBits - the actual size of the member
OffsetInBits - the number of bits between the start of the member in the layout of the structure and the start of the structure
AlignInBits - the address boundary (if any) to which the element has to be aligned.
Remember that on some processor architectures (e.g. Sun), basic data items (e.g shorts, ints, floats) have to be allocated to store at addresses which are multiples of their size; e.g. shorts must be allocated at addresses
which are multiples of two bytes, ints allocated at addresses which are multiples of 4 bytes, etc. If this rule is not followed, e.g. a 4-byte integer is allocated at an odd address, then any attempt to load or store that variable will result in a bus error. On architectures which do not have this constraint, it is sufficient for objects to be byte-aligned.
So in your example, you might have
age : size 32, offset 0, align 32
name: size 32, offset 32, align 32
age : size 32, offset 0, align 8
name: size 32, offset 32, align 8
depending on your target processor.
The sizeInBits and AliginInBits parameters to createStructType describe the whole structure (e.g. Actor: sizeInBits:64 aligInBits: 32). Note that the size of the structure may be more than the sum of the size of the individual members - there may be gaps in the structure layout, depending on the sizes and alignments of its members. The alignment of a structure is generally the largest alignment of any of its members; the structure type must be laid out so that if a structure variable starts at an address which is a multiple of the structure’s alignment then each of its members starts at an address which is a multiple of its alignment.
E.g. if you have a structure
and an int is 4 bytes and a short 2 bytes, then either you must leave a 2-byte gap between S and I2 in the layout or you must re-order the fields (if the language you are implementing allows that) so that S comes after I1 and I2 in the layout; otherwise either I1 or I2 will be misaligned in store regardless of the address at which V is allocated.
The ‘Ty’ parameter to createMemberType specifies the type of the member. In your example, you will need to create DIType objects for the types ‘int’ and ‘const char*’; use the first one in the call to createMemberType for “age” and the second one in the call for “name”.
As a general principle, when creating the DIType object for a given type, you must work from the bottom up (or recursively, from the top down) through the hierarchy of types which you are compiling : you must create the DIype for a type before you create the DItype for any other type which uses that type (e.g. as a member of a structure, or an element of an array, or the target type of a pointer type, etc.). Note that you can have cycles of type dependencies in your hierarchy; e.g. a struct S could have a field P which is of type S* - so before you try to create the DIType for a given type you must check whether you have already created it, otherwise you could recurse endlessly around the cycles! (until your stack blows up…)
Hope this helps,