static void handle_die( struct dwarf_subprogram_t **subprograms, Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_Die the_die, Dwarf_Unsigned language) { int rc; Dwarf_Error err; Dwarf_Die current_die = the_die; Dwarf_Die child_die = NULL; Dwarf_Die next_die; do { *subprograms = read_cu_entry(*subprograms, dbg, cu_die, current_die, language); /* Recursive call handle_die with child, to continue searching within child dies */ rc = dwarf_child(current_die, &child_die, &err); DWARF_ASSERT(rc, err); if (rc == DW_DLV_OK && child_die) handle_die(subprograms, dbg, cu_die, child_die, language); rc = dwarf_siblingof(dbg, current_die, &next_die, &err); DWARF_ASSERT(rc, err); dwarf_dealloc(dbg, current_die, DW_DLA_DIE); current_die = next_die; } while (rc != DW_DLV_NO_ENTRY); }
static struct dwarf_subprogram_t *read_from_cus(Dwarf_Debug dbg) { Dwarf_Unsigned cu_header_length, abbrev_offset, next_cu_header; Dwarf_Half version_stamp, address_size; Dwarf_Error err; Dwarf_Die no_die = 0, cu_die, child_die, next_die; int ret = DW_DLV_OK; int rc; struct dwarf_subprogram_t *subprograms = NULL; while (ret == DW_DLV_OK) { ret = dwarf_next_cu_header( dbg, &cu_header_length, &version_stamp, &abbrev_offset, &address_size, &next_cu_header, &err); DWARF_ASSERT(ret, err); if (ret == DW_DLV_NO_ENTRY) continue; /* TODO: If the CU can provide an address range then we can skip over * all the entire die if none of our addresses match */ /* Expect the CU to have a single sibling - a DIE */ ret = dwarf_siblingof(dbg, no_die, &cu_die, &err); if (ret == DW_DLV_ERROR) { continue; } DWARF_ASSERT(ret, err); /* Expect the CU DIE to have children */ ret = dwarf_child(cu_die, &child_die, &err); DWARF_ASSERT(ret, err); next_die = child_die; /* Now go over all children DIEs */ do { subprograms = read_cu_entry(subprograms, dbg, cu_die, child_die); rc = dwarf_siblingof(dbg, child_die, &next_die, &err); DWARF_ASSERT(rc, err); dwarf_dealloc(dbg, child_die, DW_DLA_DIE); child_die = next_die; } while (rc != DW_DLV_NO_ENTRY); dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); } return subprograms; }
static struct dwarf_subprogram_t *read_from_cus(Dwarf_Debug dbg) { Dwarf_Unsigned cu_header_length, abbrev_offset, next_cu_header; Dwarf_Half version_stamp, address_size; Dwarf_Error err; Dwarf_Die no_die = 0, cu_die, child_die; int ret = DW_DLV_OK; struct dwarf_subprogram_t *subprograms = NULL; Dwarf_Unsigned language = 0; Dwarf_Attribute language_attr = 0; while (ret == DW_DLV_OK) { ret = dwarf_next_cu_header( dbg, &cu_header_length, &version_stamp, &abbrev_offset, &address_size, &next_cu_header, &err); DWARF_ASSERT(ret, err); if (ret == DW_DLV_NO_ENTRY) continue; /* TODO: If the CU can provide an address range then we can skip over * all the entire die if none of our addresses match */ /* Expect the CU to have a single sibling - a DIE */ ret = dwarf_siblingof(dbg, no_die, &cu_die, &err); if (ret == DW_DLV_ERROR) { continue; } DWARF_ASSERT(ret, err); /* Get compilation unit language attribute */ ret = dwarf_attr(cu_die, DW_AT_language, &language_attr, &err); DWARF_ASSERT(ret, err); if (ret != DW_DLV_NO_ENTRY) { /* Get language attribute data */ ret = dwarf_formudata(language_attr, &language, &err); DWARF_ASSERT(ret, err); dwarf_dealloc(dbg, language_attr, DW_DLA_ATTR); } /* Expect the CU DIE to have children */ ret = dwarf_child(cu_die, &child_die, &err); DWARF_ASSERT(ret, err); handle_die(&subprograms, dbg, cu_die, child_die, language); dwarf_dealloc(dbg, cu_die, DW_DLA_DIE); } return subprograms; }
/* List a function if it's in the given DIE. */ static struct dwarf_subprogram_t *read_cu_entry( struct dwarf_subprogram_t *subprograms, Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_Die the_die) { char* die_name = 0; Dwarf_Error err; Dwarf_Half tag; Dwarf_Addr lowpc = 0; Dwarf_Addr highpc = 0; char *filename; struct dwarf_subprogram_t *subprogram = NULL; int rc; Dwarf_Attribute attrib = 0; rc = dwarf_tag(the_die, &tag, &err); if (rc != DW_DLV_OK) fatal("unable to parse dwarf tag"); /* Only interested in subprogram DIEs here */ if (tag != DW_TAG_subprogram) return subprograms; rc = dwarf_diename(the_die, &die_name, &err); if (rc == DW_DLV_ERROR) fatal("unable to parse dwarf diename"); if (rc == DW_DLV_NO_ENTRY) return subprograms; rc = dwarf_attr(cu_die, DW_AT_name, &attrib, &err); DWARF_ASSERT(rc, err); if (rc != DW_DLV_NO_ENTRY) { rc = dwarf_formstring(attrib, &filename, &err); DWARF_ASSERT(rc, err); dwarf_dealloc(dbg, attrib, DW_DLA_ATTR); } rc = dwarf_lowpc(the_die, &lowpc, &err); DWARF_ASSERT(rc, err); rc = dwarf_highpc(the_die, &highpc, &err); DWARF_ASSERT(rc, err); /* TODO: when would these not be defined? */ if (lowpc && highpc) { subprogram = malloc(sizeof(*subprogram)); if (!subprogram) fatal("unable to allocate memory"); memset(subprogram, 0, sizeof(*subprogram)); subprogram->lowpc = lowpc; subprogram->highpc = highpc; subprogram->name = die_name; subprogram->next = subprograms; subprograms = subprogram; } return subprograms; }
/* simple but too slow */ struct dwarf_subprogram_t *read_from_globals(Dwarf_Debug dbg) { Dwarf_Global *globals = NULL; Dwarf_Signed nglobals; Dwarf_Off offset; Dwarf_Die die; Dwarf_Addr lowpc = 0; Dwarf_Addr highpc = 0; Dwarf_Error err; Dwarf_Attribute attrib = 0; struct dwarf_subprogram_t *subprograms = NULL; struct dwarf_subprogram_t *subprogram = NULL; char *name; int i; int ret; ret = dwarf_get_globals(dbg, &globals, &nglobals, &err); DWARF_ASSERT(ret, err); if (ret != DW_DLV_OK) fatal("unable to get dwarf globals"); for (i = 0; i < nglobals; i++) { ret = dwarf_global_die_offset(globals[i], &offset, &err); DWARF_ASSERT(ret, err); /* TODO: this function does a linear search, making it pretty damn * slow.. see libdwarf/dwarf_die_deliv.c:_dwarf_find_CU_Context * for details */ ret = dwarf_offdie(dbg, offset, &die, &err); DWARF_ASSERT(ret, err); ret = dwarf_lowpc(die, &lowpc, &err); DWARF_ASSERT(ret, err); ret = dwarf_highpc(die, &highpc, &err); DWARF_ASSERT(ret, err); /* TODO: when would these not be defined? */ if (lowpc && highpc) { subprogram = malloc(sizeof(*subprogram)); if (!subprogram) fatal("unable to allocate memory for subprogram"); memset(subprogram, 0, sizeof(*subprogram)); ret = dwarf_attr(die, DW_AT_MIPS_linkage_name, &attrib, &err); if (ret == DW_DLV_OK) { ret = dwarf_formstring(attrib, &name, &err); DWARF_ASSERT(ret, err); dwarf_dealloc(dbg, attrib, DW_DLA_ATTR); } else { ret = dwarf_globname(globals[i], &name, &err); DWARF_ASSERT(ret, err); } subprogram->lowpc = lowpc; subprogram->highpc = highpc; subprogram->name = name; subprogram->next = subprograms; subprograms = subprogram; } dwarf_dealloc(dbg, die, DW_DLA_DIE); } return subprograms; }
/* The following function concatenates function parameters to the function name. in case we symbolicate a Swift compilation unit, since Swift enables mutliple overloads for the same function name */ static char* get_function_name_with_params(char *die_name, Dwarf_Die the_die, Dwarf_Debug dbg) { int rc; Dwarf_Error err; /* Allocate symbol name string buffer */ int symbol_name_buffer_length = (strlen(die_name) + 2) * 32; /* Buffer size */ char *symbol_name = malloc(symbol_name_buffer_length); if (!symbol_name) fatal("unable to allocate memory"); /* Concatenate subprogram name and " (" */ strcpy(symbol_name, die_name); strcat(symbol_name, " ("); int symbol_name_length = strlen(symbol_name); /* Actual string length */ /* Get subprogram children */ Dwarf_Die child_die = NULL; Dwarf_Die next_die; rc = dwarf_child(the_die, &child_die, &err); DWARF_ASSERT(rc, err); if (rc == DW_DLV_OK && child_die){ do { /* Get child tag */ Dwarf_Half child_tag; rc = dwarf_tag(child_die, &child_tag, &err); if (rc != DW_DLV_OK) fatal("unable to parse dwarf tag"); /* Check if child is a parameter */ if (child_tag == DW_TAG_formal_parameter) { char* param_name = 0; /* Get param name (child die name), ignoring the "self" parameter */ rc = dwarf_diename(child_die, ¶m_name, &err); if (rc == DW_DLV_OK && strcmp(param_name, "self") != 0) { /* Update actual symbol name string length */ symbol_name_length += strlen(param_name) + 2; /* Check if symbol name string buffer needs expansion */ if (symbol_name_length >= symbol_name_buffer_length - 1) /* Expand (reallocate) symbol name string buffer */ symbol_name = realloc(symbol_name, symbol_name_buffer_length *= 2); /* Concatenate param name and ", " */ strcat(symbol_name, param_name); strcat(symbol_name, ", "); } } /* Move to next sibling (param) */ rc = dwarf_siblingof(dbg, child_die, &next_die, &err); DWARF_ASSERT(rc, err); dwarf_dealloc(dbg, child_die, DW_DLA_DIE); child_die = next_die; } while (rc != DW_DLV_NO_ENTRY); } /* Remove trailing ", " if needed */ int len = strlen(symbol_name); if (symbol_name[len - 1] == ' ') { symbol_name[len - 1] = 0; symbol_name[len - 2] = 0; } strcat (symbol_name, ")"); return symbol_name; }