/* Line breaks and indentation for pretty-printing */ staticvoid process_linebreak(struct die *cache, int n)
{
indentation_level += n;
do_linebreak = true;
die_map_add_linebreak(cache, n);
}
int process_die_container(struct state *state, struct die *cache,
Dwarf_Die *die, die_callback_t func,
die_match_callback_t match)
{
Dwarf_Die current; int res;
/* Track the first item in lists. */ if (state)
state->first_list_item = true;
res = checkp(dwarf_child(die, ¤t)); while (!res) { if (match(¤t)) { /* <0 = error, 0 = continue, >0 = stop */
res = checkp(func(state, cache, ¤t)); if (res) goto out;
}
res = checkp(dwarf_siblingof(¤t, ¤t));
}
res = 0;
out: if (state)
state->first_list_item = false;
return res;
}
staticint process_type(struct state *state, struct die *parent,
Dwarf_Die *die);
staticvoid process_type_attr(struct state *state, struct die *cache,
Dwarf_Die *die)
{
Dwarf_Die type;
if (get_ref_die_attr(die, DW_AT_type, &type)) {
check(process_type(state, cache, &type)); return;
}
/* Compilers can omit DW_AT_type -- print out 'void' to clarify */
process(cache, "base_type void");
}
staticvoid process_list_comma(struct state *state, struct die *cache)
{ if (state->first_list_item) {
state->first_list_item = false;
} else {
process(cache, " ,");
process_linebreak(cache, 0);
}
}
/* Comma-separated with DW_AT_type */ staticvoid __process_list_type(struct state *state, struct die *cache,
Dwarf_Die *die, constchar *type)
{ constchar *name = get_name_attr(die);
if (stable) { if (is_kabi_prefix(name))
name = NULL;
state->kabi.orig_name = NULL;
}
staticint get_union_kabi_status(Dwarf_Die *die, Dwarf_Die *placeholder, constchar **orig_name)
{ struct state state; int res;
if (!stable) return KABI_NORMAL;
/* *TomaintainastablekABI,distributionsmaychoosetoreserve *spaceinstructsforlaterusebyaddingplaceholdermembers, *forexample: * *structs{ *u32a; *// an 8-byte placeholder for future use *u64__kabi_reserved_0; *}; * *Whenthereservedmemberistakenintouse,thetypechange *wouldnormallycausethesymbolversiontochangeaswell,but *ifthereplacementusesthefollowingconvention,gendwarfksyms *continuestousetheplaceholdertypeforversioninginstead, *thusmaintainingthesamesymbolversion: * *structs{ *u32a; *union{ *// placeholder replaced with a new member `b` *structtb; *struct{ *// the placeholder type that is still *// used for versioning *u64__kabi_reserved_0; *}; *}; *}; * *I.e.,aslongasthereplacedmemberisinaunion,andthe *placeholderhasa__kabi_reservednameprefix,we'llcontinue *tousetheplaceholdertype(hereu64)forversioncalculation *insteadoftheuniontype. * *It'salsopossibletoignorenewmembersfromversioningif *they'vebeenaddedtoalignmentholes,forexample,by *includingtheminaunionwithanothermemberthatusesthe *__kabi_ignorednameprefix: * *structs{ *u32a; *// an alignment hole is used to add `n` *union{ *u32n; *// hide the entire union member from versioning *u8__kabi_ignored_0; *}; *u64b; *}; * *Notethattheuserofthisfeatureisresponsibleforensuring *thatthestructureactuallyremainsABIcompatible.
*/
memset(&state.kabi, 0, sizeof(state.kabi));
res = checkp(process_die_container(&state, NULL, die,
check_union_member_kabi_status,
match_member_type));
if (res == KABI_RESERVED) { if (placeholder)
*placeholder = state.kabi.placeholder; if (orig_name)
*orig_name = state.kabi.orig_name;
}
staticint ___process_structure_type(struct state *state, struct die *cache,
Dwarf_Die *die)
{ switch (dwarf_tag(die)) { case DW_TAG_member: if (is_kabi_ignored(die)) return0; return check(process_type(state, cache, die)); case DW_TAG_variant_part: return check(process_type(state, cache, die)); case DW_TAG_class_type: case DW_TAG_enumeration_type: case DW_TAG_structure_type: case DW_TAG_template_type_parameter: case DW_TAG_union_type: case DW_TAG_subprogram: /* Skip non-member types, including member functions */ return0; default:
error("unexpected structure_type child: %x", dwarf_tag(die));
}
}
staticvoid __process_structure_type(struct state *state, struct die *cache,
Dwarf_Die *die, constchar *type,
die_callback_t process_func,
die_match_callback_t match_func)
{ bool expand;
staticint process_type(struct state *state, struct die *parent, Dwarf_Die *die)
{ enum die_state want_state = DIE_COMPLETE; struct die *cache; struct expansion_state saved; int tag = dwarf_tag(die);
expansion_state_save(&state->expand, &saved);
/* *Structuresandenumerationtypesareexpandedonlyonceper *exportedsymbol.ThisissufficientfordetectingABIchanges *withinthestructure.
*/ if (is_expanded_type(tag)) { if (cache_was_expanded(&state->expansion_cache, die->addr))
state->expand.expand = false;
if (state->expand.expand)
cache_mark_expanded(&state->expansion_cache, die->addr); else
want_state = DIE_UNEXPANDED;
}
staticvoid save_symbol_ptr(struct state *state)
{
Dwarf_Die ptr_type;
Dwarf_Die type;
if (!get_ref_die_attr(&state->die, DW_AT_type, &ptr_type) ||
dwarf_tag(&ptr_type) != DW_TAG_pointer_type)
error("%s must be a pointer type!",
get_symbol_name(&state->die));
if (!get_ref_die_attr(&ptr_type, DW_AT_type, &type))
error("%s pointer missing a type attribute?",
get_symbol_name(&state->die));
staticint process_exported_symbols(struct state *unused, struct die *cache,
Dwarf_Die *die)
{ int tag = dwarf_tag(die);
switch (tag) { /* Possible containers of exported symbols */ case DW_TAG_namespace: case DW_TAG_class_type: case DW_TAG_structure_type: return check(process_die_container(
NULL, cache, die, process_exported_symbols, match_all));
/* Possible exported symbols */ case DW_TAG_subprogram: case DW_TAG_variable: { struct state state;
if (!dwarf_die_addr_die(dwarf, (void *)sym->ptr_die_addr, &state.die))
error("dwarf_die_addr_die failed for symbol ptr: '%s'",
sym->name);
if (dwarf_tag(&state.die) == DW_TAG_subroutine_type)
process_subprogram(&state, &state.die); else
process_variable(&state, &state.die);
cache_free(&state.expansion_cache);
}
staticint resolve_fqns(struct state *parent, struct die *unused,
Dwarf_Die *die)
{ struct state state; struct die *cache; constchar *name; bool use_prefix; char *prefix = NULL; char *fqn = ""; int tag;
if (!__die_map_get((uintptr_t)die->addr, DIE_FQN, &cache)) return0;
tag = dwarf_tag(die);
/* *Onlynamespacesandstructuresneedtopassaprefixtothenext *scope.
*/
use_prefix = tag == DW_TAG_namespace || tag == DW_TAG_class_type ||
tag == DW_TAG_structure_type;
state.expand.current_fqn = NULL;
name = get_name_attr(die);
if (parent && parent->expand.current_fqn && (use_prefix || name)) { /* *ThefqnforthecurrentDIE,andifneeded,aprefixforthe *nextscope.
*/ if (asprintf(&prefix, "%s::%s", parent->expand.current_fqn,
name ? name : "<anonymous>") < 0)
error("asprintf failed");
if (use_prefix)
state.expand.current_fqn = prefix;
/* *UsefqnonlyiftheDIEhasaname.Otherwisefqnwill *remainempty.
*/ if (name) {
fqn = prefix; /* prefix will be freed by die_map. */
prefix = NULL;
}
} elseif (name) { /* No prefix from the previous scope. Use only the name. */
fqn = xstrdup(name);
if (use_prefix)
state.expand.current_fqn = fqn;
}
/* If the DIE has a non-empty name, cache it. */ if (*fqn) {
cache = die_map_get(die, DIE_FQN); /* Move ownership of fqn to die_map. */
cache->fqn = fqn;
cache->state = DIE_FQN;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.