libdwarf
Demonstrating reading DWARF without a file.

How to read DWARF2 and later from memory.

*/
#include <config.h>
#include <stddef.h> /* NULL */
#include <stdio.h> /* printf() */
#include <stdlib.h> /* exit() */
#include <string.h> /* strcmp() */
#include "dwarf.h"
#include "libdwarf.h"
#include "libdwarf_private.h"
/*
This demonstates processing DWARF
from in_memory data. For simplicity
in this example we are using static arrays.
The C source is src/bin/dwarfexample/jitreader.c
The motivation is from JIT compiling, where
at runtime of some application, it generates
code on the file and DWARF information for it too.
This gives an example of enabling all of libdwarf's
functions without actually having the DWARF information
in a file. (If you have a file in some odd format
you can use this approach to have libdwarf access
the format for DWARF data and work normally without
ever exposing the format to libdwarf.)
None of the structures defined here in this source
(or any source using this feature)
are ever known to libdwarf. They are totally
private to your code.
The code you write (like this example) you compile
separate from libdwarf. You never place your code
into libdwarf, you just link your code into
your application and link against libdwarf.
*/
/* Some valid DWARF2 data */
static Dwarf_Small abbrevbytes[] = {
0x01, 0x11, 0x01, 0x25, 0x0e, 0x13, 0x0b, 0x03, 0x08, 0x1b,
0x0e, 0x11, 0x01, 0x12, 0x01, 0x10, 0x06, 0x00, 0x00, 0x02,
0x2e, 0x01, 0x3f, 0x0c, 0x03, 0x08, 0x3a, 0x0b, 0x3b, 0x0b,
0x39, 0x0b, 0x27, 0x0c, 0x11, 0x01, 0x12, 0x01, 0x40, 0x06,
0x97, 0x42, 0x0c, 0x01, 0x13, 0x00, 0x00, 0x03, 0x34, 0x00,
0x03, 0x08, 0x3a, 0x0b, 0x3b, 0x0b, 0x39, 0x0b, 0x49, 0x13,
0x02, 0x0a, 0x00, 0x00, 0x04, 0x24, 0x00, 0x0b, 0x0b, 0x3e,
0x0b, 0x03, 0x08, 0x00, 0x00, 0x00, };
static Dwarf_Small infobytes[] = {
0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x74, 0x2e, 0x63,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x66, 0x00, 0x01,
0x02, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x5c, 0x00, 0x00, 0x00, 0x03, 0x69,
0x00, 0x01, 0x03, 0x08, 0x5c, 0x00, 0x00, 0x00, 0x02, 0x91,
0x6c, 0x00, 0x04, 0x04, 0x05, 0x69, 0x6e, 0x74, 0x00, 0x00, };
static Dwarf_Small strbytes[] = {
0x47, 0x4e, 0x55, 0x20, 0x43, 0x31, 0x37, 0x20, 0x39, 0x2e,
0x33, 0x2e, 0x30, 0x20, 0x2d, 0x6d, 0x74, 0x75, 0x6e, 0x65,
0x3d, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x20, 0x2d,
0x6d, 0x61, 0x72, 0x63, 0x68, 0x3d, 0x78, 0x38, 0x36, 0x2d,
0x36, 0x34, 0x20, 0x2d, 0x67, 0x64, 0x77, 0x61, 0x72, 0x66,
0x2d, 0x32, 0x20, 0x2d, 0x4f, 0x30, 0x20, 0x2d, 0x66, 0x61,
0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x75,
0x73, 0x2d, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x2d, 0x74,
0x61, 0x62, 0x6c, 0x65, 0x73, 0x20, 0x2d, 0x66, 0x73, 0x74,
0x61, 0x63, 0x6b, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63,
0x74, 0x6f, 0x72, 0x2d, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67,
0x20, 0x2d, 0x66, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2d, 0x63,
0x6c, 0x61, 0x73, 0x68, 0x2d, 0x70, 0x72, 0x6f, 0x74, 0x65,
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x2d, 0x66, 0x63, 0x66,
0x2d, 0x70, 0x72, 0x6f, 0x74, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x00, 0x2f, 0x76, 0x61, 0x72, 0x2f, 0x74, 0x6d, 0x70,
0x2f, 0x74, 0x69, 0x6e, 0x79, 0x64, 0x77, 0x61, 0x72, 0x66,
0x00, };
/* An internals_t , data used elsewhere but
not directly visible elsewhere. One needs to have one
of these but maybe the content here too little
or useless, this is just an example of sorts. */
#define SECCOUNT 4
struct sectiondata_s {
unsigned int sd_addr;
unsigned int sd_objoffsetlen;
unsigned int sd_objpointersize;
Dwarf_Unsigned sd_sectionsize;
const char * sd_secname;
Dwarf_Small * sd_content;
};
/* The secname must not be 0 , pass "" if
there is no name. */
static struct sectiondata_s sectiondata[SECCOUNT] = {
{0,0,0,0,"",0},
{0,32,32,sizeof(abbrevbytes),".debug_abbrev",abbrevbytes},
{0,32,32,sizeof(infobytes),".debug_info",infobytes},
{0,32,32,sizeof(strbytes),".debug_str",strbytes}
};
typedef struct special_filedata_s {
int f_is_64bit;
Dwarf_Small f_object_endian;
unsigned f_pointersize;
unsigned f_offsetsize;
Dwarf_Unsigned f_filesize;
Dwarf_Unsigned f_sectioncount;
struct sectiondata_s * f_sectarray;
} special_filedata_internals_t;
/* Use DW_END_little.
Libdwarf finally sets the file-format-specific
f_object_endianness field to a DW_END_little or
DW_END_big (see dwarf.h).
Here we must do that ourselves. */
static special_filedata_internals_t base_internals =
{ FALSE,DW_END_little,32,32,200,SECCOUNT, sectiondata };
static
int gsinfo(void* obj,
Dwarf_Unsigned section_index,
Dwarf_Obj_Access_Section_a* return_section,
int* error )
{
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
struct sectiondata_s *finfo = 0;
*error = 0; /* No error. Avoids unused arg */
if (section_index >= SECCOUNT) {
return DW_DLV_NO_ENTRY;
}
finfo = internals->f_sectarray + section_index;
return_section->as_name = finfo->sd_secname;
return_section->as_type = 0;
return_section->as_flags = 0;
return_section->as_addr = finfo->sd_addr;
return_section->as_offset = 0;
return_section->as_size = finfo->sd_sectionsize;
return_section->as_link = 0;
return_section->as_info = 0;
return_section->as_addralign = 0;
return_section->as_entrysize = 1;
return DW_DLV_OK;
}
gborder(void * obj)
{
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_object_endian;
}
static
Dwarf_Small glensize(void * obj)
{
/* offset size */
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_offsetsize/8;
}
static
Dwarf_Small gptrsize(void * obj)
{
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_pointersize/8;
}
static
Dwarf_Unsigned gfilesize(void * obj)
{
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_filesize;
}
static
Dwarf_Unsigned gseccount(void* obj)
{
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_sectioncount;
}
static
int gloadsec(void * obj,
Dwarf_Unsigned secindex,
Dwarf_Small**rdata,
int *error)
{
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
struct sectiondata_s *secp = 0;
*error = 0; /* No Error, avoids compiler warning */
if (secindex >= internals->f_sectioncount) {
return DW_DLV_NO_ENTRY;
}
secp = secindex +internals->f_sectarray;
*rdata = secp->sd_content;
return DW_DLV_OK;
}
const Dwarf_Obj_Access_Methods_a methods = {
gsinfo,
gborder,
glensize,
gptrsize,
gfilesize,
gseccount,
gloadsec,
0 /* no relocating anything */
};
struct Dwarf_Obj_Access_Interface_a_s dw_interface =
{ &base_internals,&methods };
static const Dwarf_Sig8 zerosignature;
static int
isformstring(Dwarf_Half form)
{
/* Not handling every form string, just the
ones used in simple cases. */
switch(form) {
case DW_FORM_string: return TRUE;
case DW_FORM_GNU_strp_alt: return TRUE;
case DW_FORM_GNU_str_index: return TRUE;
case DW_FORM_strx: return TRUE;
case DW_FORM_strx1: return TRUE;
case DW_FORM_strx2: return TRUE;
case DW_FORM_strx3: return TRUE;
case DW_FORM_strx4: return TRUE;
case DW_FORM_strp: return TRUE;
default: break;
};
return FALSE;
}
static int
print_attr(Dwarf_Attribute atr,
Dwarf_Signed anumber, Dwarf_Error *error)
{
int res = 0;
char *str = 0;
const char *attrname = 0;
const char *formname = 0;
Dwarf_Half form = 0;
Dwarf_Half attrnum = 0;
res = dwarf_whatform(atr,&form,error);
if (res != DW_DLV_OK) {
printf("dwarf_whatform failed! res %d\n",res);
return res;
}
res = dwarf_whatattr(atr,&attrnum,error);
if (res != DW_DLV_OK) {
printf("dwarf_whatattr failed! res %d\n",res);
return res;
}
res = dwarf_get_AT_name(attrnum,&attrname);
if (res == DW_DLV_NO_ENTRY) {
printf("Bogus attrnum 0x%x\n",attrnum);
attrname = "<internal error ?>";
}
res = dwarf_get_FORM_name(form,&formname);
if (res == DW_DLV_NO_ENTRY) {
printf("Bogus form 0x%x\n",attrnum);
attrname = "<internal error ?>";
}
if (!isformstring(form)) {
printf(" [%2d] Attr: %-15s Form: %-15s\n",
(int)anumber,attrname,formname);
return DW_DLV_OK;
}
res = dwarf_formstring(atr,&str,error);
if (res != DW_DLV_OK) {
printf("dwarf_formstring failed! res %d\n",res);
return res;
}
printf(" [%2d] Attr: %-15s Form: %-15s %s\n",
(int)anumber,attrname,formname,str);
return DW_DLV_OK;
}
static void
dealloc_list(Dwarf_Debug dbg,
Dwarf_Attribute *attrbuf,
Dwarf_Signed attrcount,
{
for ( ; i < attrcount; ++i) {
}
dwarf_dealloc(dbg,attrbuf,DW_DLA_LIST);
}
static int
print_one_die(Dwarf_Debug dbg,Dwarf_Die in_die,int level,
Dwarf_Error *error)
{
Dwarf_Attribute *attrbuf = 0;
Dwarf_Signed attrcount = 0;
Dwarf_Half tag = 0;
const char * tagname = 0;
int res = 0;
Dwarf_Signed i = 0;
res = dwarf_tag(in_die,&tag,error);
if (res != DW_DLV_OK) {
printf("dwarf_tag failed! res %d\n",res);
return res;
}
res = dwarf_get_TAG_name(tag,&tagname);
if (res != DW_DLV_OK) {
tagname = "<bogus tag>";
}
printf("%3d: Die: %s\n",level,tagname);
res = dwarf_attrlist(in_die,&attrbuf,&attrcount,error);
if (res != DW_DLV_OK) {
printf("dwarf_attrlist failed! res %d\n",res);
return res;
}
for (i = 0; i <attrcount;++i) {
res =print_attr(attrbuf[i],i,error);
if (res != DW_DLV_OK) {
dealloc_list(dbg,attrbuf,attrcount,0);
printf("dwarf_attr print failed! res %d\n",res);
return res;
}
}
dealloc_list(dbg,attrbuf,attrcount,0);
return DW_DLV_OK;
}
static int
print_object_info(Dwarf_Debug dbg,Dwarf_Error *error)
{
Dwarf_Bool is_info = TRUE; /* our data is not DWARF4
.debug_types. */
Dwarf_Unsigned cu_header_length = 0;
Dwarf_Half version_stamp = 0;
Dwarf_Off abbrev_offset = 0;
Dwarf_Half address_size = 0;
Dwarf_Half length_size = 0;
Dwarf_Half extension_size = 0;
Dwarf_Sig8 type_signature;
Dwarf_Unsigned typeoffset = 0;
Dwarf_Unsigned next_cu_header_offset = 0;
Dwarf_Half header_cu_type = 0;
int res = 0;
Dwarf_Die cu_die = 0;
int level = 0;
type_signature = zerosignature;
is_info,
&cu_header_length,
&version_stamp,
&abbrev_offset,
&address_size,
&length_size,
&extension_size,
&type_signature,
&typeoffset,
&next_cu_header_offset,
&header_cu_type,
error);
if (res != DW_DLV_OK) {
printf("Next cu header result %d. "
"Something is wrong FAIL, line %d\n",res,__LINE__);
if (res == DW_DLV_ERROR) {
printf("Error is: %s\n",dwarf_errmsg(*error));
}
exit(EXIT_FAILURE);
}
printf("CU header length..........0x%lx\n",
(unsigned long)cu_header_length);
printf("Version stamp.............%d\n",version_stamp);
printf("Address size .............%d\n",address_size);
printf("Offset size...............%d\n",length_size);
printf("Next cu header offset.....0x%lx\n",
(unsigned long)next_cu_header_offset);
res = dwarf_siblingof_b(dbg, NULL,is_info, &cu_die, error);
if (res != DW_DLV_OK) {
/* There is no CU die, which should be impossible. */
if (res == DW_DLV_ERROR) {
printf("ERROR: dwarf_siblingof_b failed, no CU die\n");
printf("Error is: %s\n",dwarf_errmsg(*error));
return res;
} else {
printf("ERROR: dwarf_siblingof_b got NO_ENTRY, "
"no CU die\n");
return res;
}
}
res = print_one_die(dbg,cu_die,level,error);
if (res != DW_DLV_OK) {
printf("print_one_die failed! %d\n",res);
return res;
}
return DW_DLV_OK;
}
/* testing interfaces useful for embedding
libdwarf inside another program or library. */
int main(int argc, char **argv)
{
int res = 0;
Dwarf_Debug dbg = 0;
Dwarf_Error error = 0;
int fail = FALSE;
int i = 1;
if (i >= argc) {
/* OK */
} else {
if (!strcmp(argv[i],"--suppress-de-alloc-tree")) {
/* Do nothing, ignore the argument */
++i;
}
}
/* Fill in interface before this call.
We are using a static area, see above. */
res = dwarf_object_init_b(&dw_interface,
0,0,DW_GROUPNUMBER_ANY,&dbg,
&error);
if (res == DW_DLV_NO_ENTRY) {
printf("FAIL Cannot dwarf_object_init_b() NO ENTRY. \n");
exit(EXIT_FAILURE);
} else if (res == DW_DLV_ERROR){
printf("FAIL Cannot dwarf_object_init_b(). \n");
printf("msg: %s\n",dwarf_errmsg(error));
dwarf_dealloc_error(dbg,error);
exit(EXIT_FAILURE);
}
res = print_object_info(dbg,&error);
if (res != DW_DLV_OK) {
if (res == DW_DLV_ERROR) {
dwarf_dealloc_error(dbg,error);
}
printf("FAIL printing, res %d line %d\n",res,__LINE__);
exit(EXIT_FAILURE);
}
if (fail) {
printf("FAIL objectaccess.c\n");
exit(EXIT_FAILURE);
}
return 0;
}
int dwarf_get_FORM_name(unsigned int dw_val_in, const char **dw_s_out)
dwarf_get_FORM_name
int dwarf_get_TAG_name(unsigned int dw_val_in, const char **dw_s_out)
dwarf_get_TAG_name
int dwarf_get_AT_name(unsigned int dw_val_in, const char **dw_s_out)
dwarf_get_AT_name
struct Dwarf_Debug_s * Dwarf_Debug
Definition: libdwarf.h:586
struct Dwarf_Die_s * Dwarf_Die
Definition: libdwarf.h:591
struct Dwarf_Error_s * Dwarf_Error
Definition: libdwarf.h:580
struct Dwarf_Attribute_s * Dwarf_Attribute
Definition: libdwarf.h:641
void dwarf_dealloc_attribute(Dwarf_Attribute dw_attr)
Dealloc a Dwarf_Attribute When this call returns the dw_attr is a stale pointer.
int dwarf_whatform(Dwarf_Attribute dw_attr, Dwarf_Half *dw_returned_final_form, Dwarf_Error *dw_error)
Return the form of the Dwarf_Attribute.
int dwarf_formstring(Dwarf_Attribute dw_attr, char **dw_returned_string, Dwarf_Error *dw_error)
Return a pointer to a string.
int dwarf_attrlist(Dwarf_Die dw_die, Dwarf_Attribute **dw_attrbuf, Dwarf_Signed *dw_attrcount, Dwarf_Error *dw_error)
Gets the full list of attributes.
int dwarf_whatattr(Dwarf_Attribute dw_attr, Dwarf_Half *dw_returned_attrnum, Dwarf_Error *dw_error)
Return the attribute number of the Dwarf_Attribute.
unsigned char Dwarf_Small
Definition: libdwarf.h:204
signed long long Dwarf_Signed
Definition: libdwarf.h:197
unsigned short Dwarf_Half
Definition: libdwarf.h:203
unsigned long long Dwarf_Unsigned
Definition: libdwarf.h:196
int Dwarf_Bool
Definition: libdwarf.h:202
unsigned long long Dwarf_Off
Definition: libdwarf.h:198
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_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.
int dwarf_tag(Dwarf_Die dw_die, Dwarf_Half *dw_return_tag, Dwarf_Error *dw_error)
Get TAG value of 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,...
void dwarf_dealloc_error(Dwarf_Debug dw_dbg, Dwarf_Error dw_error)
Free (dealloc) an Dwarf_Error something created.
char * dwarf_errmsg(Dwarf_Error dw_error)
What message string is in the error?
int dwarf_object_init_b(Dwarf_Obj_Access_Interface_a *dw_obj, Dwarf_Handler dw_errhand, Dwarf_Ptr dw_errarg, unsigned int dw_groupnumber, Dwarf_Debug *dw_dbg, Dwarf_Error *dw_error)
Used to access DWARF information in memory or in an object format unknown to libdwarf.
int dwarf_object_finish(Dwarf_Debug dw_dbg)
Used to close the object_init dw_dbg.
Definition: libdwarf.h:798
Definition: libdwarf.h:779
Definition: libdwarf.h:761
Definition: libdwarf.h:303