[RFC] Aggregate mapping

Jim Tison jtison@ntplx.net
Sun Jun 10 16:56:00 GMT 2007


It was suggested that I post an RFC here. With advance apologies for its 
length, I am looking for comments, remarks, and/or advice.

I'm currently trying to code a C language structure for a complex block 
of 0x200 bytes in size from a paper document. This particular 
declaration is rife with bitfields, mis-aligned base datatypes, and 
reserved fields. What I need is to verify my coding against the paper 
document before I start testing code which uses it. I've looked through 
gcc documents and find nothing which fits this need: no obvious -d pass 
which would give me such a map, nor any other option or standalone 
program. I'm proposing to create a standalone program, as I don't know 
enough about gcc internals to force such maps to be generated during 
compilation ... I'm not certain this would be appropriate, anyway. OTOH, 
I can't be the first to propose solving this problem.

AFAICT, the only accurate source data for such an aggregate map would be 
DWARF DIE entries. This would mean that I'd be post-processing ELF 
objects generated with the -g switch. What I'd like to end up with is a 
program which is portable among ELF types and outputs accurate data when 
run on foreign CPU architectures; much like readelf attempts to. This 
means I'd need to generically handle Elf64 and Elf32 formats, as well as 
respect endianism. I'd like this program to be able to properly extract 
aggregate maps from the three basic ELF types: relocatable, absolute, 
and DSO.

I've done some reading of the DWARF-2 and DWARF-3 standards. What I see 
emitted as DWARF in gcc-4.1.x is marked as DWARF-2; but I'm told that 
gcc properly emits DWARF-3. Should I even check the version? Will I need 
to vary processing features by gcc level?

Since I'm targeting all three ELF object types, I'm thinking I have to 
start reading the sections .debug_info and .debug_abbrev at the DWARF CU 
level, and build a tree of CU-related data. I've actually started this 
bit of code and am somewhat happy with test results so far.

DWARF isn't exactly user-friendly for my purposes. I've built, read 
about, and attempted to grok libdwarf ... I have to confess that I don't 
quite get it; but I think I have a functional understanding of how DWARF 
data is laid out and related within gcc-emitted objects. Therefore, I'm 
planning to not use libdwarf except for its DW_* pp terms in libdwarf.h. 
I expect to hear that I should be using gcc/dwarf.h; but I'd need to be 
convinced that its enum type forms are versatile enough to use in decoding.

Nor am I planning to use libelf: it's too straightforward to find the 
ELF sections I need and to read the ELF header. Use of libelf seems too 
top-heavy, although elf.h is very valuable to me.

I don't know enough about Fortran, Ada, or Java to even be conversant in 
how these languages aggregate; if this program supports these languages, 
it will be accidentally. I'm starting with C language dialects 
(DW_LANG_C, DW_LANG_C89, DW_LANG_C99) and intend to add support for C++ 
once C function testing is complete -- C++ classes add complexity that I 
really don't want to deal with during initial development.

Here's the high-level functional design I've got so far:
  1. Read the ELF object file, determine its type, endianism, and 
bitness as written. Find the .shstrtab section, and point at the section 
headers. Through the section headers, find the .debug_info and 
.debug_abbrev sections. Read them into memory and make these copies 
persistent through the rest of this program's lifecycle.
  2. Index through the DWARF CU headers (in .debug_info) and determine a 
count of CUs.
  3. For each CU,
    (3a) Create an array of pointers into .debug_abbrev, reading the 
DW_TAGs as we go. For each DW_TAG_{structure_type, union_type}, mark the 
abbrev index item as "of interest".
    (3b) Iterate through .debug_info DIEs as delimited for the current 
CU, looking for abbreviation numbers we've marked as "of interest". For 
each interesting DIE,
    (3c) Preserve source filename/path of declaration, starting line 
number, aggregate type (struct/union), tag (if any), and total length. 
Now, work its child DIEs (members). For each:
    (3d) Report byte offset, byte length, bit offset, and bit length as 
available. [I don't particularly like the way bit offsets are reported 
within multi-byte bitfields, so I expect to do some division by 8 and 
adjust the byte offset as appropriate. If I can't fix this to the point 
where it makes sense for both endianisms, then I'll abandon this tweak.] 
Report the base type and identifier of the member.
    (3e) If there's a typedef associated with this aggregate type, 
identify its name and save it.
4. When all CUs have been extracted, display all extracted information 
about the aggregates and their members, appropriately grouped.

Where I've run into trouble so far is attempting to predict what kind of 
storage I'll need to save all this intermediate summary data. DWARF 
sections can get rather large, and there's no way to predict the 
contents until they're read. I expect this program -- if I follow the 
design -- to use large amounts of memory until I get to the point where 
I can start releasing blocks by displaying what they represent. Would I 
be making things easier on myself (or orders of magnitude less versatile 
for the user) by processing ELF relocatables only? [This seems a dead 
end to me, but I thought I'd ask anyway.]

I don't intend to use language syntax features in the display -- I don't 
plan on "recoding" structure declarations in C ... I just plan on 
displaying a few lines about each overall aggregate, and then listing 
the important characteristics of each of its members in row/column 
format ... then inject a few linefeeds and proceed to the next 
aggregate. I'm hoping this will increase the chances of "accidental" 
language support.

I'd appreciate comments. If anybody has a handle on the future of gcc & 
DWARF (am I wasting my time?), additional features (have I got the right 
scope?), or just general "been there, done that ... watch out for ..." 
kind of remarks, then I'm listening. Am I trying to hit a moving target 
wrt DWARF content? I'd also like to hear if anybody has a better idea 
other than DWARF data as the source for this kind of process ... is 
there a gcc phase I've missed? What features would *you* like to see in 
an aggregate mapper?

/Of course/ I'll contribute this, assuming my employer's Legal staff 
will permit me to do so, you guys want it, and the code doesn't end up a 
maintenance or licensing nightmare.

Please post replies to the list.

TIA,
---Jim--



More information about the Gcc mailing list