libdwarf
Example walking CUs(d)

Example accessing all CUs looking for specific items(d).

Loops through as many CUs as needed, stops and returns once a CU provides the desired data.

Assumes certain functions you write to remember the aspect of CUs that matter to you so once found in a cu my_needed_data_exists() or some other function of yours can identify the correct record. (Possibly a DIE global offset. Remember to note if each DIE has is_info TRUE or FALSE so libdwarf can find the DIE properly.)

Depending on your goals in examining the DIE tree it may be helpful to maintain a DIE stack of active DIEs, pushing and popping as you make your way throught the DIE levels.

We assume that on a serious error we will give up (for simplicity here).

We assume the caller to examplecuhdrd() will know what to retrieve (when we return DW_DLV_OK from examplecuhdrd() and that myrecords points to a record with all the data needed by my_needed_data_exists() and recorded by myrecord_data_for_die().

*/
struct myrecords_struct *myrecords;
void myrecord_data_for_die(struct myrecords_struct *myrecords,
int my_needed_data_exists(struct myrecords_struct *myrecords);
/* Loop on DIE tree. */
static void
record_die_and_siblingsd(Dwarf_Debug dbg, Dwarf_Die in_die,
int is_info, int in_level,
struct myrecords_struct *myrec,
Dwarf_Error *error)
{
int res = DW_DLV_OK;
Dwarf_Die cur_die=in_die;
Dwarf_Die child = 0;
myrecord_data_for_die(myrec,in_die);
/* Loop on a list of siblings */
for (;;) {
Dwarf_Die sib_die = 0;
/* Depending on your goals, the in_level,
and the DW_TAG of cur_die, you may want
to skip the dwarf_child call. */
res = dwarf_child(cur_die,&child,error);
if (res == DW_DLV_ERROR) {
printf("Error in dwarf_child , level %d \n",in_level);
exit(EXIT_FAILURE);
}
if (res == DW_DLV_OK) {
record_die_and_siblingsd(dbg,child,is_info,
in_level+1,myrec,error);
/* No longer need 'child' die. */
dwarf_dealloc(dbg,child,DW_DLA_DIE);
child = 0;
}
/* res == DW_DLV_NO_ENTRY or DW_DLV_OK */
res = dwarf_siblingof_b(dbg,cur_die,is_info,&sib_die,error);
if (res == DW_DLV_ERROR) {
exit(EXIT_FAILURE);
}
if (res == DW_DLV_NO_ENTRY) {
/* Done at this level. */
break;
}
/* res == DW_DLV_OK */
if (cur_die != in_die) {
dwarf_dealloc(dbg,cur_die,DW_DLA_DIE);
cur_die = 0;
}
cur_die = sib_die;
myrecord_data_for_die(myrec,sib_die);
}
return;
}
/* Assuming records properly initialized for your use. */
int examplecuhdrd(Dwarf_Debug dbg,
struct myrecords_struct *myrec,
Dwarf_Error *error)
{
Dwarf_Unsigned abbrev_offset = 0;
Dwarf_Half address_size = 0;
Dwarf_Half version_stamp = 0;
Dwarf_Half offset_size = 0;
Dwarf_Half extension_size = 0;
Dwarf_Sig8 signature;
Dwarf_Unsigned typeoffset = 0;
Dwarf_Unsigned next_cu_header = 0;
Dwarf_Half header_cu_type = 0;
Dwarf_Bool is_info = TRUE;
int res = 0;
while(!my_needed_data_exists(myrec)) {
Dwarf_Die no_die = 0;
Dwarf_Die cu_die = 0;
Dwarf_Unsigned cu_header_length = 0;
memset(&signature,0, sizeof(signature));
res = dwarf_next_cu_header_d(dbg,is_info,&cu_header_length,
&version_stamp, &abbrev_offset,
&address_size, &offset_size,
&extension_size,&signature,
&typeoffset, &next_cu_header,
&header_cu_type,error);
if (res == DW_DLV_ERROR) {
return res;
}
if (res == DW_DLV_NO_ENTRY) {
if (is_info == TRUE) {
/* Done with .debug_info, now check for
.debug_types. */
is_info = FALSE;
continue;
}
/* No more CUs to read! Never found
what we were looking for in either
.debug_info or .debug_types. */
return res;
}
/* The CU will have a single sibling, a cu_die.
It is essential to call this right after
a call to dwarf_next_cu_header_d() because
there is no explicit connection provided to
dwarf_siblingof_b(), which returns a DIE
from whatever CU was last accessed by
dwarf_next_cu_header_d()!
The lack of explicit connection was a
design mistake in the API (made in 1992). */
res = dwarf_siblingof_b(dbg,no_die,is_info,
&cu_die,error);
if (res == DW_DLV_ERROR) {
return res;
}
if (res == DW_DLV_NO_ENTRY) {
/* Impossible */
exit(EXIT_FAILURE);
}
record_die_and_siblingsd(dbg,cu_die,is_info,
0, myrec,error);
}
/* Found what we looked for */
return DW_DLV_OK;
}
struct Dwarf_Debug_s * Dwarf_Debug
Definition: libdwarf.h:603
struct Dwarf_Die_s * Dwarf_Die
Definition: libdwarf.h:608
struct Dwarf_Error_s * Dwarf_Error
Definition: libdwarf.h:597
unsigned short Dwarf_Half
Definition: libdwarf.h:203
unsigned long long Dwarf_Unsigned
Definition: libdwarf.h:196
int Dwarf_Bool
Definition: libdwarf.h:202
int dwarf_next_cu_header_d(Dwarf_Debug dw_dbg, Dwarf_Bool dw_is_info, Dwarf_Unsigned *dw_cu_header_length, Dwarf_Half *dw_version_stamp, Dwarf_Off *dw_abbrev_offset, Dwarf_Half *dw_address_size, Dwarf_Half *dw_length_size, Dwarf_Half *dw_extension_size, Dwarf_Sig8 *dw_type_signature, Dwarf_Unsigned *dw_typeoffset, Dwarf_Unsigned *dw_next_cu_header_offset, Dwarf_Half *dw_header_cu_type, Dwarf_Error *dw_error)
Return information on the next CU header(d)
void dwarf_dealloc_die(Dwarf_Die dw_die)
Deallocate (free) a DIE.
int dwarf_child(Dwarf_Die dw_die, Dwarf_Die *dw_return_childdie, Dwarf_Error *dw_error)
Return the child DIE, if any. The child may be the first of a list of sibling DIEs.
int dwarf_siblingof_b(Dwarf_Debug dw_dbg, Dwarf_Die dw_die, Dwarf_Bool dw_is_info, Dwarf_Die *dw_return_siblingdie, Dwarf_Error *dw_error)
Return the first DIE or the next sibling DIE.
void dwarf_dealloc(Dwarf_Debug dw_dbg, void *dw_space, Dwarf_Unsigned dw_type)
The generic dealloc (free) function. It requires you know the correct DW_DLA value to pass in,...
Definition: libdwarf.h:313