Jitreader Demonstrating DWARF without a file.
#include <config.h>
#include <stddef.h> /* NULL */
#include <stdio.h> /* printf() */
#include <stdlib.h> /* exit() */
#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] = {
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 };
int gsinfo(void* obj,
Dwarf_Half 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) {
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;
Dwarf_Small glensize(void * obj)
/* offset size */
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_offsetsize/8;
Dwarf_Small gptrsize(void * obj)
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_pointersize/8;
Dwarf_Unsigned gfilesize(void * obj)
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_filesize;
Dwarf_Unsigned gseccount(void* obj)
special_filedata_internals_t *internals =
(special_filedata_internals_t *)(obj);
return internals->f_sectioncount;
int gloadsec(void * obj,
Dwarf_Half secindex,
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) {
secp = secindex +internals->f_sectarray;
*rdata = secp->sd_content;
return DW_DLV_OK;
const Dwarf_Obj_Access_Methods_a methods = {
0 /* no relocating anything */
{ &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",
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",
return DW_DLV_OK;
static int
print_one_die(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) {
printf("dwarf_attr print failed! res %d\n",res);
return res;
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;
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));
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(cu_die,level,error);
if (res != DW_DLV_OK) {
printf("print_one_die failed! %d\n",res);
if (res == DW_DLV_ERROR) {
printf("Error is: %s\n",dwarf_errmsg(*error));
return DW_DLV_OK;
/* testing interfaces useful for embedding
libdwarf inside another program or library. */
int main(void)
int res = 0;
Dwarf_Debug dbg = 0;
Dwarf_Error error = 0;
int fail = FALSE;
/* Fill in iface before this call.
We are using a static area, see above. */
res = dwarf_object_init_b(&interface,
if (res != DW_DLV_OK) {
if (res == DW_DLV_NO_ENTRY) {
printf("FAIL Cannot dwarf_object_init_b() NO ENTRY. \n");
} else {
printf("FAIL Cannot dwarf_object_init_b(). \n");
printf("msg: %s\n",dwarf_errmsg(error));
res = print_object_info(dbg,&error);
if (res != DW_DLV_OK) {
printf("FAIL printing, res %d line %d\n",res,__LINE__);
if (fail) {
printf("FAIL objectaccess.c\n");
return 0;
unsigned char Dwarf_Small
Definition: libdwarf.h:217
int Dwarf_Bool
Definition: libdwarf.h:215
unsigned short Dwarf_Half
Definition: libdwarf.h:216
char * dwarf_errmsg(Dwarf_Error dw_error)
What message string is in the error?
Definition: libdwarf.h:698
Definition: libdwarf.h:717
struct Dwarf_Debug_s * Dwarf_Debug
Definition: libdwarf.h:537
int dwarf_get_AT_name(unsigned int dw_val_in, const char **dw_s_out)
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_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_get_TAG_name(unsigned int dw_val_in, const char **dw_s_out)
struct Dwarf_Attribute_s * Dwarf_Attribute
Definition: libdwarf.h:571
unsigned long long Dwarf_Off
Definition: libdwarf.h:211
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)
Retrieve the first DIE or the next sibling.
int dwarf_whatform(Dwarf_Attribute dw_attr, Dwarf_Half *dw_returned_final_form, Dwarf_Error *dw_error)
Returns the form of the Dwarf_Attribute.
int dwarf_get_FORM_name(unsigned int dw_val_in, const char **dw_s_out)
Definition: libdwarf.h:316
Definition: libdwarf.h:680
unsigned long long Dwarf_Unsigned
Definition: libdwarf.h:209
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)
Returns information on the next CU header.
signed long long Dwarf_Signed
Definition: libdwarf.h:210
struct Dwarf_Die_s * Dwarf_Die
Definition: libdwarf.h:542
int dwarf_whatattr(Dwarf_Attribute dw_attr, Dwarf_Half *dw_returned_attrnum, Dwarf_Error *dw_error)
Returns the attribute number of the Dwarf_Attribute.
int dwarf_formstring(Dwarf_Attribute dw_attr, char **dw_returned_string, Dwarf_Error *dw_error)
Returns a pointer to a string.
int dwarf_object_finish(Dwarf_Debug dw_dbg)
Used to close the object_init dw_dbg.
int dwarf_tag(Dwarf_Die dw_die, Dwarf_Half *dw_return_tag, Dwarf_Error *dw_error)
Get TAG value of DIE.
struct Dwarf_Error_s * Dwarf_Error
Definition: libdwarf.h:531