/* SPDX-License-Identifier: GPL-2.0 *//* * Convert sample address to data type using DWARF debug info. * * Written by Namhyung Kim <namhyung@kernel.org> */ #include <stdio.h>#include <stdlib.h>#include <inttypes.h>#include <linux/zalloc.h> #include "annotate.h"#include "annotate-data.h"#include "debuginfo.h"#include "debug.h"#include "dso.h"#include "dwarf-regs.h"#include "evsel.h"#include "evlist.h"#include "map.h"#include "map_symbol.h"#include "sort.h"#include "strbuf.h"#include "symbol.h"#include "symbol_conf.h"#include "thread.h" /* register number of the stack pointer */#define X86_REG_SP 7 static void delete_var_types(struct die_var_type *var_types); #define pr_debug_dtp(fmt, ...) \do { \ if (debug_type_profile) \ pr_info(fmt, ##__VA_ARGS__); \ else \ pr_debug3(fmt, ##__VA_ARGS__); \} while (0) void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind){ struct strbuf sb; char *str; Dwarf_Word size = 0; if (!debug_type_profile && verbose < 3) return; switch (kind) { case TSR_KIND_INVALID: pr_info("\n"); return; case TSR_KIND_PERCPU_BASE: pr_info(" percpu base\n"); return; case TSR_KIND_CONST: pr_info(" constant\n"); return; case TSR_KIND_POINTER: pr_info(" pointer"); /* it also prints the type info */ break; case TSR_KIND_CANARY: pr_info(" stack canary\n"); return; case TSR_KIND_TYPE: default: break; } dwarf_aggregate_size(die, &size); strbuf_init(&sb, 32); die_get_typename_from_type(die, &sb); str = strbuf_detach(&sb, NULL); pr_info(" type='%s' size=%#lx (die:%#lx)\n", str, (long)size, (long)dwarf_dieoffset(die)); free(str);} static void pr_debug_location(Dwarf_Die *die, u64 pc, int reg){ ptrdiff_t off = 0; Dwarf_Attribute attr; Dwarf_Addr base, start, end; Dwarf_Op *ops; size_t nops; if (!debug_type_profile && verbose < 3) return; if (dwarf_attr(die, DW_AT_location, &attr) == NULL) return; while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) { if (reg != DWARF_REG_PC && end <= pc) continue; if (reg != DWARF_REG_PC && start > pc) break; pr_info(" variable location: "); switch (ops->atom) { case DW_OP_reg0 ...DW_OP_reg31: pr_info("reg%d\n", ops->atom - DW_OP_reg0); break; case DW_OP_breg0 ...DW_OP_breg31: pr_info("base=reg%d, offset=%#lx\n", ops->atom - DW_OP_breg0, (long)ops->number); break; case DW_OP_regx: pr_info("reg%ld\n", (long)ops->number); break; case DW_OP_bregx: pr_info("base=reg%ld, offset=%#lx\n", (long)ops->number, (long)ops->number2); break; case DW_OP_fbreg: pr_info("use frame base, offset=%#lx\n", (long)ops->number); break; case DW_OP_addr: pr_info("address=%#lx\n", (long)ops->number); break; default: pr_info("unknown: code=%#x, number=%#lx\n", ops->atom, (long)ops->number); break; } break; }} static void pr_debug_scope(Dwarf_Die *scope_die){ int tag; if (!debug_type_profile && verbose < 3) return; pr_info("(die:%lx) ", (long)dwarf_dieoffset(scope_die)); tag = dwarf_tag(scope_die); if (tag == DW_TAG_subprogram) pr_info("[function] %s\n", dwarf_diename(scope_die)); else if (tag == DW_TAG_inlined_subroutine) pr_info("[inlined] %s\n", dwarf_diename(scope_die)); else if (tag == DW_TAG_lexical_block) pr_info("[block]\n"); else pr_info("[unknown] tag=%x\n", tag);} bool has_reg_type(struct type_state *state, int reg){ return (unsigned)reg < ARRAY_SIZE(state->regs);} static void init_type_state(struct type_state *state, struct arch *arch){ memset(state, 0, sizeof(*state)); INIT_LIST_HEAD(&state->stack_vars); if (arch__is(arch, "x86")) { state->regs[0].caller_saved = true; state->regs[1].caller_saved = true; state->regs[2].caller_saved = true; state->regs[4].caller_saved = true; state->regs[5].caller_saved = true; state->regs[8].caller_saved = true; state->regs[9].caller_saved = true; state->regs[10].caller_saved = true; state->regs[11].caller_saved = true; state->ret_reg = 0; state->stack_reg = X86_REG_SP; }} static void exit_type_state(struct type_state *state){ struct type_state_stack *stack, *tmp; list_for_each_entry_safe(stack, tmp, &state->stack_vars, list) { list_del(&stack->list); free(stack); }} /* * Compare type name and size to maintain them in a tree. * I'm not sure if DWARF would have information of a single type in many * different places (compilation units). If not, it could compare the * offset of the type entry in the .debug_info section. */static int data_type_cmp(const void *_key, const struct rb_node *node){ const struct annotated_data_type *key = _key; struct annotated_data_type *type; type = rb_entry(node, struct annotated_data_type, node); if (key->self.size != type->self.size) return key->self.size - type->self.size; return strcmp(key->self.type_name, type->self.type_name);} static bool data_type_less(struct rb_node *node_a, const struct rb_node *node_b){ struct annotated_data_type *a, *b; a = rb_entry(node_a, struct annotated_data_type, node); b = rb_entry(node_b, struct annotated_data_type, node); if (a->self.size != b->self.size) return a->self.size < b->self.size; return strcmp(a->self.type_name, b->self.type_name) < 0;} /* Recursively add new members for struct/union */static int __add_member_cb(Dwarf_Die *die, void *arg){ struct annotated_member *parent = arg; struct annotated_member *member; Dwarf_Die member_type, die_mem; Dwarf_Word size, loc, bit_size = 0; Dwarf_Attribute attr; struct strbuf sb; int tag; if (dwarf_tag(die) != DW_TAG_member) return DIE_FIND_CB_SIBLING; member = zalloc(sizeof(*member)); if (member == NULL) return DIE_FIND_CB_END; strbuf_init(&sb, 32); die_get_typename(die, &sb); __die_get_real_type(die, &member_type); if (dwarf_tag(&member_type) == DW_TAG_typedef) die_get_real_type(&member_type, &die_mem); else die_mem = member_type; if (dwarf_aggregate_size(&die_mem, &size) < 0) size = 0; if (dwarf_attr_integrate(die, DW_AT_data_member_location, &attr)) dwarf_formudata(&attr, &loc); else { /* bitfield member */ if (dwarf_attr_integrate(die, DW_AT_data_bit_offset, &attr) && dwarf_formudata(&attr, &loc) == 0) loc /= 8; else loc = 0; if (dwarf_attr_integrate(die, DW_AT_bit_size, &attr) && dwarf_formudata(&attr, &bit_size) == 0) size = (bit_size + 7) / 8; } member->type_name = strbuf_detach(&sb, NULL); /* member->var_name can be NULL */ if (dwarf_diename(die)) { if (bit_size) { if (asprintf(&member->var_name, "%s:%ld", dwarf_diename(die), (long)bit_size) < 0) member->var_name = NULL; } else { member->var_name = strdup(dwarf_diename(die)); } if (member->var_name == NULL) { free(member); return DIE_FIND_CB_END; } } member->size = size; member->offset = loc + parent->offset; INIT_LIST_HEAD(&member->children); list_add_tail(&member->node, &parent->children); tag = dwarf_tag(&die_mem); switch (tag) { case DW_TAG_structure_type: case DW_TAG_union_type: die_find_child(&die_mem, __add_member_cb, member, &die_mem); break; default: break; } return DIE_FIND_CB_SIBLING;} static void add_member_types(struct annotated_data_type *parent, Dwarf_Die *type){ Dwarf_Die die_mem; die_find_child(type, __add_member_cb, &parent->self, &die_mem);} static void delete_members(struct annotated_member *member){ struct annotated_member *child, *tmp; list_for_each_entry_safe(child, tmp, &member->children, node) { list_del(&child->node); delete_members(child); zfree(&child->type_name); zfree(&child->var_name); free(child); }} static struct annotated_data_type *dso__findnew_data_type(struct dso *dso, Dwarf_Die *type_die){ struct annotated_data_type *result = NULL; struct annotated_data_type key; struct rb_node *node; struct strbuf sb; char *type_name; Dwarf_Word size; strbuf_init(&sb, 32); if (die_get_typename_from_type(type_die, &sb) < 0) strbuf_add(&sb, "(unknown type)", 14); type_name = strbuf_detach(&sb, NULL); if (dwarf_tag(type_die) == DW_TAG_typedef) die_get_real_type(type_die, type_die); dwarf_aggregate_size(type_die, &size); /* Check existing nodes in dso->data_types tree */ key.self.type_name = type_name; key.self.size = size; node = rb_find(&key, dso__data_types(dso), data_type_cmp); if (node) { result = rb_entry(node, struct annotated_data_type, node); free(type_name); return result; } /* If not, add a new one */ result = zalloc(sizeof(*result)); if (result == NULL) { free(type_name); return NULL; } result->self.type_name = type_name; result->self.size = size; INIT_LIST_HEAD(&result->self.children); if (symbol_conf.annotate_data_member) add_member_types(result, type_die); rb_add(&result->node, dso__data_types(dso), data_type_less); return result;} static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die){ Dwarf_Off off, next_off; size_t header_size; if (dwarf_addrdie(di->dbg, pc, cu_die) != NULL) return cu_die; /* * There are some kernels don't have full aranges and contain only a few * aranges entries. Fallback to iterate all CU entries in .debug_info * in case it's missing. */ off = 0; while (dwarf_nextcu(di->dbg, off, &next_off, &header_size, NULL, NULL, NULL) == 0) { if (dwarf_offdie(di->dbg, off + header_size, cu_die) && dwarf_haspc(cu_die, pc)) return true; off = next_off; } return false;} enum type_match_result { PERF_TMR_UNKNOWN = 0, PERF_TMR_OK, PERF_TMR_NO_TYPE, PERF_TMR_NO_POINTER, PERF_TMR_NO_SIZE, PERF_TMR_BAD_OFFSET, PERF_TMR_BAIL_OUT,}; static const char *match_result_str(enum type_match_result tmr){ switch (tmr) { case PERF_TMR_OK: return "Good!"; case PERF_TMR_NO_TYPE: return "no type information"; case PERF_TMR_NO_POINTER: return "no/void pointer"; case PERF_TMR_NO_SIZE: return "type size is unknown"; case PERF_TMR_BAD_OFFSET: return "offset bigger than size"; case PERF_TMR_UNKNOWN: case PERF_TMR_BAIL_OUT: default: return "invalid state"; }} static bool is_pointer_type(Dwarf_Die *type_die){ int tag = dwarf_tag(type_die); return tag == DW_TAG_pointer_type || tag == DW_TAG_array_type;} static bool is_compound_type(Dwarf_Die *type_die){ int tag = dwarf_tag(type_die); return tag == DW_TAG_structure_type || tag == DW_TAG_union_type;} /* returns if Type B has better information than Type A */static bool is_better_type(Dwarf_Die *type_a, Dwarf_Die *type_b){ Dwarf_Word size_a, size_b; Dwarf_Die die_a, die_b; /* pointer type is preferred */ if (is_pointer_type(type_a) != is_pointer_type(type_b)) return is_pointer_type(type_b); if (is_pointer_type(type_b)) { /* * We want to compare the target type, but 'void *' can fail to * get the target type. */ if (die_get_real_type(type_a, &die_a) == NULL) return true; if (die_get_real_type(type_b, &die_b) == NULL) return false; type_a = &die_a; type_b = &die_b; } /* bigger type is preferred */ if (dwarf_aggregate_size(type_a, &size_a) < 0 || dwarf_aggregate_size(type_b, &size_b) < 0) return false; if (size_a != size_b) return size_a < size_b; /* struct or union is preferred */ if (is_compound_type(type_a) != is_compound_type(type_b)) return is_compound_type(type_b); /* typedef is preferred */ if (dwarf_tag(type_b) == DW_TAG_typedef) return true; return false;} /* The type info will be saved in @type_die */static enum type_match_result check_variable(struct data_loc_info *dloc, Dwarf_Die *var_die, Dwarf_Die *type_die, int reg, int offset, bool is_fbreg){ Dwarf_Word size; bool needs_pointer = true; Dwarf_Die sized_type; if (reg == DWARF_REG_PC) needs_pointer = false; else if (reg == dloc->fbreg || is_fbreg) needs_pointer = false; else if (arch__is(dloc->arch, "x86") && reg == X86_REG_SP) needs_pointer = false; /* Get the type of the variable */ if (__die_get_real_type(var_die, type_die) == NULL) return PERF_TMR_NO_TYPE; /* * Usually it expects a pointer type for a memory access. * Convert to a real type it points to. But global variablesLines 1–500 of 1828. Load more
/* SPDX-License-Identifier: GPL-2.0 */ /* * Convert sample address to data type using DWARF debug info. * * Written by Namhyung Kim <namhyung@kernel.org> */ #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include <linux/zalloc.h> #include "annotate.h" #include "annotate-data.h" #include "debuginfo.h" #include "debug.h" #include "dso.h" #include "dwarf-regs.h" #include "evsel.h" #include "evlist.h" #include "map.h" #include "map_symbol.h" #include "sort.h" #include "strbuf.h" #include "symbol.h" #include "symbol_conf.h" #include "thread.h" /* register number of the stack pointer */ #define X86_REG_SP 7 static void delete_var_types(struct die_var_type *var_types); #define pr_debug_dtp(fmt, ...) \ do { \ if (debug_type_profile) \ pr_info(fmt, ##__VA_ARGS__); \ else \ pr_debug3(fmt, ##__VA_ARGS__); \ } while (0) void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) { struct strbuf sb; char *str; Dwarf_Word size = 0; if (!debug_type_profile && verbose < 3) return; switch (kind) { case TSR_KIND_INVALID: pr_info("\n"); return; case TSR_KIND_PERCPU_BASE: pr_info(" percpu base\n"); return; case TSR_KIND_CONST: pr_info(" constant\n"); return; case TSR_KIND_POINTER: pr_info(" pointer"); /* it also prints the type info */ break; case TSR_KIND_CANARY: pr_info(" stack canary\n"); return; case TSR_KIND_TYPE: default: break; } dwarf_aggregate_size(die, &size); strbuf_init(&sb, 32); die_get_typename_from_type(die, &sb); str = strbuf_detach(&sb, NULL); pr_info(" type='%s' size=%#lx (die:%#lx)\n", str, (long)size, (long)dwarf_dieoffset(die)); free(str); } static void pr_debug_location(Dwarf_Die *die, u64 pc, int reg) { ptrdiff_t off = 0; Dwarf_Attribute attr; Dwarf_Addr base, start, end; Dwarf_Op *ops; size_t nops; if (!debug_type_profile && verbose < 3) return; if (dwarf_attr(die, DW_AT_location, &attr) == NULL) return; while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) { if (reg != DWARF_REG_PC && end <= pc) continue; if (reg != DWARF_REG_PC && start > pc) break; pr_info(" variable location: "); switch (ops->atom) { case DW_OP_reg0 ...DW_OP_reg31: pr_info("reg%d\n", ops->atom - DW_OP_reg0); break; case DW_OP_breg0 ...DW_OP_breg31: pr_info("base=reg%d, offset=%#lx\n", ops->atom - DW_OP_breg0, (long)ops->number); break; case DW_OP_regx: pr_info("reg%ld\n", (long)ops->number); break; case DW_OP_bregx: pr_info("base=reg%ld, offset=%#lx\n", (long)ops->number, (long)ops->number2); break; case DW_OP_fbreg: pr_info("use frame base, offset=%#lx\n", (long)ops->number); break; case DW_OP_addr: pr_info("address=%#lx\n", (long)ops->number); break; default: pr_info("unknown: code=%#x, number=%#lx\n", ops->atom, (long)ops->number); break; } break; } } static void pr_debug_scope(Dwarf_Die *scope_die) { int tag; if (!debug_type_profile && verbose < 3) return; pr_info("(die:%lx) ", (long)dwarf_dieoffset(scope_die)); tag = dwarf_tag(scope_die); if (tag == DW_TAG_subprogram) pr_info("[function] %s\n", dwarf_diename(scope_die)); else if (tag == DW_TAG_inlined_subroutine) pr_info("[inlined] %s\n", dwarf_diename(scope_die)); else if (tag == DW_TAG_lexical_block) pr_info("[block]\n"); else pr_info("[unknown] tag=%x\n", tag); } bool has_reg_type(struct type_state *state, int reg) { return (unsigned)reg < ARRAY_SIZE(state->regs); } static void init_type_state(struct type_state *state, struct arch *arch) { memset(state, 0, sizeof(*state)); INIT_LIST_HEAD(&state->stack_vars); if (arch__is(arch, "x86")) { state->regs[0].caller_saved = true; state->regs[1].caller_saved = true; state->regs[2].caller_saved = true; state->regs[4].caller_saved = true; state->regs[5].caller_saved = true; state->regs[8].caller_saved = true; state->regs[9].caller_saved = true; state->regs[10].caller_saved = true; state->regs[11].caller_saved = true; state->ret_reg = 0; state->stack_reg = X86_REG_SP; } } static void exit_type_state(struct type_state *state) { struct type_state_stack *stack, *tmp; list_for_each_entry_safe(stack, tmp, &state->stack_vars, list) { list_del(&stack->list); free(stack); } } /* * Compare type name and size to maintain them in a tree. * I'm not sure if DWARF would have information of a single type in many * different places (compilation units). If not, it could compare the * offset of the type entry in the .debug_info section. */ static int data_type_cmp(const void *_key, const struct rb_node *node) { const struct annotated_data_type *key = _key; struct annotated_data_type *type; type = rb_entry(node, struct annotated_data_type, node); if (key->self.size != type->self.size) return key->self.size - type->self.size; return strcmp(key->self.type_name, type->self.type_name); } static bool data_type_less(struct rb_node *node_a, const struct rb_node *node_b) { struct annotated_data_type *a, *b; a = rb_entry(node_a, struct annotated_data_type, node); b = rb_entry(node_b, struct annotated_data_type, node); if (a->self.size != b->self.size) return a->self.size < b->self.size; return strcmp(a->self.type_name, b->self.type_name) < 0; } /* Recursively add new members for struct/union */ static int __add_member_cb(Dwarf_Die *die, void *arg) { struct annotated_member *parent = arg; struct annotated_member *member; Dwarf_Die member_type, die_mem; Dwarf_Word size, loc, bit_size = 0; Dwarf_Attribute attr; struct strbuf sb; int tag; if (dwarf_tag(die) != DW_TAG_member) return DIE_FIND_CB_SIBLING; member = zalloc(sizeof(*member)); if (member == NULL) return DIE_FIND_CB_END; strbuf_init(&sb, 32); die_get_typename(die, &sb); __die_get_real_type(die, &member_type); if (dwarf_tag(&member_type) == DW_TAG_typedef) die_get_real_type(&member_type, &die_mem); else die_mem = member_type; if (dwarf_aggregate_size(&die_mem, &size) < 0) size = 0; if (dwarf_attr_integrate(die, DW_AT_data_member_location, &attr)) dwarf_formudata(&attr, &loc); else { /* bitfield member */ if (dwarf_attr_integrate(die, DW_AT_data_bit_offset, &attr) && dwarf_formudata(&attr, &loc) == 0) loc /= 8; else loc = 0; if (dwarf_attr_integrate(die, DW_AT_bit_size, &attr) && dwarf_formudata(&attr, &bit_size) == 0) size = (bit_size + 7) / 8; } member->type_name = strbuf_detach(&sb, NULL); /* member->var_name can be NULL */ if (dwarf_diename(die)) { if (bit_size) { if (asprintf(&member->var_name, "%s:%ld", dwarf_diename(die), (long)bit_size) < 0) member->var_name = NULL; } else { member->var_name = strdup(dwarf_diename(die)); } if (member->var_name == NULL) { free(member); return DIE_FIND_CB_END; } } member->size = size; member->offset = loc + parent->offset; INIT_LIST_HEAD(&member->children); list_add_tail(&member->node, &parent->children); tag = dwarf_tag(&die_mem); switch (tag) { case DW_TAG_structure_type: case DW_TAG_union_type: die_find_child(&die_mem, __add_member_cb, member, &die_mem); break; default: break; } return DIE_FIND_CB_SIBLING; } static void add_member_types(struct annotated_data_type *parent, Dwarf_Die *type) { Dwarf_Die die_mem; die_find_child(type, __add_member_cb, &parent->self, &die_mem); } static void delete_members(struct annotated_member *member) { struct annotated_member *child, *tmp; list_for_each_entry_safe(child, tmp, &member->children, node) { list_del(&child->node); delete_members(child); zfree(&child->type_name); zfree(&child->var_name); free(child); } } static struct annotated_data_type *dso__findnew_data_type(struct dso *dso, Dwarf_Die *type_die) { struct annotated_data_type *result = NULL; struct annotated_data_type key; struct rb_node *node; struct strbuf sb; char *type_name; Dwarf_Word size; strbuf_init(&sb, 32); if (die_get_typename_from_type(type_die, &sb) < 0) strbuf_add(&sb, "(unknown type)", 14); type_name = strbuf_detach(&sb, NULL); if (dwarf_tag(type_die) == DW_TAG_typedef) die_get_real_type(type_die, type_die); dwarf_aggregate_size(type_die, &size); /* Check existing nodes in dso->data_types tree */ key.self.type_name = type_name; key.self.size = size; node = rb_find(&key, dso__data_types(dso), data_type_cmp); if (node) { result = rb_entry(node, struct annotated_data_type, node); free(type_name); return result; } /* If not, add a new one */ result = zalloc(sizeof(*result)); if (result == NULL) { free(type_name); return NULL; } result->self.type_name = type_name; result->self.size = size; INIT_LIST_HEAD(&result->self.children); if (symbol_conf.annotate_data_member) add_member_types(result, type_die); rb_add(&result->node, dso__data_types(dso), data_type_less); return result; } static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die) { Dwarf_Off off, next_off; size_t header_size; if (dwarf_addrdie(di->dbg, pc, cu_die) != NULL) return cu_die; /* * There are some kernels don't have full aranges and contain only a few * aranges entries. Fallback to iterate all CU entries in .debug_info * in case it's missing. */ off = 0; while (dwarf_nextcu(di->dbg, off, &next_off, &header_size, NULL, NULL, NULL) == 0) { if (dwarf_offdie(di->dbg, off + header_size, cu_die) && dwarf_haspc(cu_die, pc)) return true; off = next_off; } return false; } enum type_match_result { PERF_TMR_UNKNOWN = 0, PERF_TMR_OK, PERF_TMR_NO_TYPE, PERF_TMR_NO_POINTER, PERF_TMR_NO_SIZE, PERF_TMR_BAD_OFFSET, PERF_TMR_BAIL_OUT, }; static const char *match_result_str(enum type_match_result tmr) { switch (tmr) { case PERF_TMR_OK: return "Good!"; case PERF_TMR_NO_TYPE: return "no type information"; case PERF_TMR_NO_POINTER: return "no/void pointer"; case PERF_TMR_NO_SIZE: return "type size is unknown"; case PERF_TMR_BAD_OFFSET: return "offset bigger than size"; case PERF_TMR_UNKNOWN: case PERF_TMR_BAIL_OUT: default: return "invalid state"; } } static bool is_pointer_type(Dwarf_Die *type_die) { int tag = dwarf_tag(type_die); return tag == DW_TAG_pointer_type || tag == DW_TAG_array_type; } static bool is_compound_type(Dwarf_Die *type_die) { int tag = dwarf_tag(type_die); return tag == DW_TAG_structure_type || tag == DW_TAG_union_type; } /* returns if Type B has better information than Type A */ static bool is_better_type(Dwarf_Die *type_a, Dwarf_Die *type_b) { Dwarf_Word size_a, size_b; Dwarf_Die die_a, die_b; /* pointer type is preferred */ if (is_pointer_type(type_a) != is_pointer_type(type_b)) return is_pointer_type(type_b); if (is_pointer_type(type_b)) { /* * We want to compare the target type, but 'void *' can fail to * get the target type. */ if (die_get_real_type(type_a, &die_a) == NULL) return true; if (die_get_real_type(type_b, &die_b) == NULL) return false; type_a = &die_a; type_b = &die_b; } /* bigger type is preferred */ if (dwarf_aggregate_size(type_a, &size_a) < 0 || dwarf_aggregate_size(type_b, &size_b) < 0) return false; if (size_a != size_b) return size_a < size_b; /* struct or union is preferred */ if (is_compound_type(type_a) != is_compound_type(type_b)) return is_compound_type(type_b); /* typedef is preferred */ if (dwarf_tag(type_b) == DW_TAG_typedef) return true; return false; } /* The type info will be saved in @type_die */ static enum type_match_result check_variable(struct data_loc_info *dloc, Dwarf_Die *var_die, Dwarf_Die *type_die, int reg, int offset, bool is_fbreg) { Dwarf_Word size; bool needs_pointer = true; Dwarf_Die sized_type; if (reg == DWARF_REG_PC) needs_pointer = false; else if (reg == dloc->fbreg || is_fbreg) needs_pointer = false; else if (arch__is(dloc->arch, "x86") && reg == X86_REG_SP) needs_pointer = false; /* Get the type of the variable */ if (__die_get_real_type(var_die, type_die) == NULL) return PERF_TMR_NO_TYPE; /* * Usually it expects a pointer type for a memory access. * Convert to a real type it points to. But global variables