1b9c87f53SNamhyung Kim /* SPDX-License-Identifier: GPL-2.0 */
2b9c87f53SNamhyung Kim /*
3b9c87f53SNamhyung Kim * Convert sample address to data type using DWARF debug info.
4b9c87f53SNamhyung Kim *
5b9c87f53SNamhyung Kim * Written by Namhyung Kim <[email protected]>
6b9c87f53SNamhyung Kim */
7b9c87f53SNamhyung Kim
8b9c87f53SNamhyung Kim #include <stdio.h>
9b9c87f53SNamhyung Kim #include <stdlib.h>
10b9c87f53SNamhyung Kim #include <inttypes.h>
1169fb6eabSArnaldo Carvalho de Melo #include <linux/zalloc.h>
12b9c87f53SNamhyung Kim
13d3030191SNamhyung Kim #include "annotate.h"
14b9c87f53SNamhyung Kim #include "annotate-data.h"
15b9c87f53SNamhyung Kim #include "debuginfo.h"
16b9c87f53SNamhyung Kim #include "debug.h"
17b9c87f53SNamhyung Kim #include "dso.h"
1883bfa06dSNamhyung Kim #include "dwarf-regs.h"
199bd7ddd1SNamhyung Kim #include "evsel.h"
209bd7ddd1SNamhyung Kim #include "evlist.h"
21b9c87f53SNamhyung Kim #include "map.h"
22b9c87f53SNamhyung Kim #include "map_symbol.h"
239b561be1SNamhyung Kim #include "sort.h"
24b9c87f53SNamhyung Kim #include "strbuf.h"
25b9c87f53SNamhyung Kim #include "symbol.h"
26263925bfSNamhyung Kim #include "symbol_conf.h"
271ebb5e17SNamhyung Kim #include "thread.h"
28b9c87f53SNamhyung Kim
29a5a00497SNamhyung Kim /* register number of the stack pointer */
30a5a00497SNamhyung Kim #define X86_REG_SP 7
31a5a00497SNamhyung Kim
32c1da8411SNamhyung Kim static void delete_var_types(struct die_var_type *var_types);
33c1da8411SNamhyung Kim
3490429524SNamhyung Kim #define pr_debug_dtp(fmt, ...) \
3590429524SNamhyung Kim do { \
3690429524SNamhyung Kim if (debug_type_profile) \
3790429524SNamhyung Kim pr_info(fmt, ##__VA_ARGS__); \
3890429524SNamhyung Kim else \
3990429524SNamhyung Kim pr_debug3(fmt, ##__VA_ARGS__); \
4090429524SNamhyung Kim } while (0)
4190429524SNamhyung Kim
pr_debug_type_name(Dwarf_Die * die,enum type_state_kind kind)42782959acSAthira Rajeev void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind)
4390429524SNamhyung Kim {
4490429524SNamhyung Kim struct strbuf sb;
4590429524SNamhyung Kim char *str;
462bc3cf57SNamhyung Kim Dwarf_Word size = 0;
4790429524SNamhyung Kim
4890429524SNamhyung Kim if (!debug_type_profile && verbose < 3)
4990429524SNamhyung Kim return;
5090429524SNamhyung Kim
51f5b09592SNamhyung Kim switch (kind) {
52f5b09592SNamhyung Kim case TSR_KIND_INVALID:
53f5b09592SNamhyung Kim pr_info("\n");
54f5b09592SNamhyung Kim return;
55f5b09592SNamhyung Kim case TSR_KIND_PERCPU_BASE:
56f5b09592SNamhyung Kim pr_info(" percpu base\n");
57f5b09592SNamhyung Kim return;
58eb9190afSNamhyung Kim case TSR_KIND_CONST:
59eb9190afSNamhyung Kim pr_info(" constant\n");
60eb9190afSNamhyung Kim return;
61eb9190afSNamhyung Kim case TSR_KIND_POINTER:
62eb9190afSNamhyung Kim pr_info(" pointer");
63eb9190afSNamhyung Kim /* it also prints the type info */
64eb9190afSNamhyung Kim break;
65b3c95109SNamhyung Kim case TSR_KIND_CANARY:
66b3c95109SNamhyung Kim pr_info(" stack canary\n");
67b3c95109SNamhyung Kim return;
68f5b09592SNamhyung Kim case TSR_KIND_TYPE:
69f5b09592SNamhyung Kim default:
70f5b09592SNamhyung Kim break;
71f5b09592SNamhyung Kim }
72f5b09592SNamhyung Kim
732bc3cf57SNamhyung Kim dwarf_aggregate_size(die, &size);
742bc3cf57SNamhyung Kim
7590429524SNamhyung Kim strbuf_init(&sb, 32);
7690429524SNamhyung Kim die_get_typename_from_type(die, &sb);
7790429524SNamhyung Kim str = strbuf_detach(&sb, NULL);
782bc3cf57SNamhyung Kim pr_info(" type='%s' size=%#lx (die:%#lx)\n",
792bc3cf57SNamhyung Kim str, (long)size, (long)dwarf_dieoffset(die));
8090429524SNamhyung Kim free(str);
8190429524SNamhyung Kim }
8290429524SNamhyung Kim
pr_debug_location(Dwarf_Die * die,u64 pc,int reg)832bc3cf57SNamhyung Kim static void pr_debug_location(Dwarf_Die *die, u64 pc, int reg)
842bc3cf57SNamhyung Kim {
852bc3cf57SNamhyung Kim ptrdiff_t off = 0;
862bc3cf57SNamhyung Kim Dwarf_Attribute attr;
872bc3cf57SNamhyung Kim Dwarf_Addr base, start, end;
882bc3cf57SNamhyung Kim Dwarf_Op *ops;
892bc3cf57SNamhyung Kim size_t nops;
902bc3cf57SNamhyung Kim
912bc3cf57SNamhyung Kim if (!debug_type_profile && verbose < 3)
922bc3cf57SNamhyung Kim return;
932bc3cf57SNamhyung Kim
942bc3cf57SNamhyung Kim if (dwarf_attr(die, DW_AT_location, &attr) == NULL)
952bc3cf57SNamhyung Kim return;
962bc3cf57SNamhyung Kim
972bc3cf57SNamhyung Kim while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) {
983ab0b8b2SNamhyung Kim if (reg != DWARF_REG_PC && end <= pc)
992bc3cf57SNamhyung Kim continue;
1002bc3cf57SNamhyung Kim if (reg != DWARF_REG_PC && start > pc)
1012bc3cf57SNamhyung Kim break;
1022bc3cf57SNamhyung Kim
1032bc3cf57SNamhyung Kim pr_info(" variable location: ");
1042bc3cf57SNamhyung Kim switch (ops->atom) {
1052bc3cf57SNamhyung Kim case DW_OP_reg0 ...DW_OP_reg31:
1062bc3cf57SNamhyung Kim pr_info("reg%d\n", ops->atom - DW_OP_reg0);
1072bc3cf57SNamhyung Kim break;
1082bc3cf57SNamhyung Kim case DW_OP_breg0 ...DW_OP_breg31:
1092bc3cf57SNamhyung Kim pr_info("base=reg%d, offset=%#lx\n",
1102bc3cf57SNamhyung Kim ops->atom - DW_OP_breg0, (long)ops->number);
1112bc3cf57SNamhyung Kim break;
1122bc3cf57SNamhyung Kim case DW_OP_regx:
1132bc3cf57SNamhyung Kim pr_info("reg%ld\n", (long)ops->number);
1142bc3cf57SNamhyung Kim break;
1152bc3cf57SNamhyung Kim case DW_OP_bregx:
1162bc3cf57SNamhyung Kim pr_info("base=reg%ld, offset=%#lx\n",
1172bc3cf57SNamhyung Kim (long)ops->number, (long)ops->number2);
1182bc3cf57SNamhyung Kim break;
1192bc3cf57SNamhyung Kim case DW_OP_fbreg:
1202bc3cf57SNamhyung Kim pr_info("use frame base, offset=%#lx\n", (long)ops->number);
1212bc3cf57SNamhyung Kim break;
1222bc3cf57SNamhyung Kim case DW_OP_addr:
1232bc3cf57SNamhyung Kim pr_info("address=%#lx\n", (long)ops->number);
1242bc3cf57SNamhyung Kim break;
1252bc3cf57SNamhyung Kim default:
1262bc3cf57SNamhyung Kim pr_info("unknown: code=%#x, number=%#lx\n",
1272bc3cf57SNamhyung Kim ops->atom, (long)ops->number);
1282bc3cf57SNamhyung Kim break;
1292bc3cf57SNamhyung Kim }
1302bc3cf57SNamhyung Kim break;
1312bc3cf57SNamhyung Kim }
1322bc3cf57SNamhyung Kim }
1332bc3cf57SNamhyung Kim
pr_debug_scope(Dwarf_Die * scope_die)13402648783SNamhyung Kim static void pr_debug_scope(Dwarf_Die *scope_die)
13502648783SNamhyung Kim {
13602648783SNamhyung Kim int tag;
13702648783SNamhyung Kim
13802648783SNamhyung Kim if (!debug_type_profile && verbose < 3)
13902648783SNamhyung Kim return;
14002648783SNamhyung Kim
14102648783SNamhyung Kim pr_info("(die:%lx) ", (long)dwarf_dieoffset(scope_die));
14202648783SNamhyung Kim
14302648783SNamhyung Kim tag = dwarf_tag(scope_die);
14402648783SNamhyung Kim if (tag == DW_TAG_subprogram)
14502648783SNamhyung Kim pr_info("[function] %s\n", dwarf_diename(scope_die));
14602648783SNamhyung Kim else if (tag == DW_TAG_inlined_subroutine)
14702648783SNamhyung Kim pr_info("[inlined] %s\n", dwarf_diename(scope_die));
14802648783SNamhyung Kim else if (tag == DW_TAG_lexical_block)
14902648783SNamhyung Kim pr_info("[block]\n");
15002648783SNamhyung Kim else
15102648783SNamhyung Kim pr_info("[unknown] tag=%x\n", tag);
15202648783SNamhyung Kim }
15302648783SNamhyung Kim
has_reg_type(struct type_state * state,int reg)1541d303deeSAthira Rajeev bool has_reg_type(struct type_state *state, int reg)
15506b2ce75SNamhyung Kim {
15606b2ce75SNamhyung Kim return (unsigned)reg < ARRAY_SIZE(state->regs);
15706b2ce75SNamhyung Kim }
15806b2ce75SNamhyung Kim
init_type_state(struct type_state * state,struct arch * arch)159eb8a55e0SNamhyung Kim static void init_type_state(struct type_state *state, struct arch *arch)
16006b2ce75SNamhyung Kim {
16106b2ce75SNamhyung Kim memset(state, 0, sizeof(*state));
16206b2ce75SNamhyung Kim INIT_LIST_HEAD(&state->stack_vars);
163cffb7910SNamhyung Kim
164cffb7910SNamhyung Kim if (arch__is(arch, "x86")) {
165cffb7910SNamhyung Kim state->regs[0].caller_saved = true;
166cffb7910SNamhyung Kim state->regs[1].caller_saved = true;
167cffb7910SNamhyung Kim state->regs[2].caller_saved = true;
168cffb7910SNamhyung Kim state->regs[4].caller_saved = true;
169cffb7910SNamhyung Kim state->regs[5].caller_saved = true;
170cffb7910SNamhyung Kim state->regs[8].caller_saved = true;
171cffb7910SNamhyung Kim state->regs[9].caller_saved = true;
172cffb7910SNamhyung Kim state->regs[10].caller_saved = true;
173cffb7910SNamhyung Kim state->regs[11].caller_saved = true;
174cffb7910SNamhyung Kim state->ret_reg = 0;
175a5a00497SNamhyung Kim state->stack_reg = X86_REG_SP;
176cffb7910SNamhyung Kim }
17706b2ce75SNamhyung Kim }
17806b2ce75SNamhyung Kim
exit_type_state(struct type_state * state)179eb8a55e0SNamhyung Kim static void exit_type_state(struct type_state *state)
18006b2ce75SNamhyung Kim {
18106b2ce75SNamhyung Kim struct type_state_stack *stack, *tmp;
18206b2ce75SNamhyung Kim
18306b2ce75SNamhyung Kim list_for_each_entry_safe(stack, tmp, &state->stack_vars, list) {
18406b2ce75SNamhyung Kim list_del(&stack->list);
18506b2ce75SNamhyung Kim free(stack);
18606b2ce75SNamhyung Kim }
18706b2ce75SNamhyung Kim }
18806b2ce75SNamhyung Kim
189fc044c53SNamhyung Kim /*
190fc044c53SNamhyung Kim * Compare type name and size to maintain them in a tree.
191fc044c53SNamhyung Kim * I'm not sure if DWARF would have information of a single type in many
192fc044c53SNamhyung Kim * different places (compilation units). If not, it could compare the
193fc044c53SNamhyung Kim * offset of the type entry in the .debug_info section.
194fc044c53SNamhyung Kim */
data_type_cmp(const void * _key,const struct rb_node * node)195fc044c53SNamhyung Kim static int data_type_cmp(const void *_key, const struct rb_node *node)
196fc044c53SNamhyung Kim {
197fc044c53SNamhyung Kim const struct annotated_data_type *key = _key;
198fc044c53SNamhyung Kim struct annotated_data_type *type;
199fc044c53SNamhyung Kim
200fc044c53SNamhyung Kim type = rb_entry(node, struct annotated_data_type, node);
201fc044c53SNamhyung Kim
2024a111cadSNamhyung Kim if (key->self.size != type->self.size)
2034a111cadSNamhyung Kim return key->self.size - type->self.size;
2044a111cadSNamhyung Kim return strcmp(key->self.type_name, type->self.type_name);
205fc044c53SNamhyung Kim }
206fc044c53SNamhyung Kim
data_type_less(struct rb_node * node_a,const struct rb_node * node_b)207fc044c53SNamhyung Kim static bool data_type_less(struct rb_node *node_a, const struct rb_node *node_b)
208fc044c53SNamhyung Kim {
209fc044c53SNamhyung Kim struct annotated_data_type *a, *b;
210fc044c53SNamhyung Kim
211fc044c53SNamhyung Kim a = rb_entry(node_a, struct annotated_data_type, node);
212fc044c53SNamhyung Kim b = rb_entry(node_b, struct annotated_data_type, node);
213fc044c53SNamhyung Kim
2144a111cadSNamhyung Kim if (a->self.size != b->self.size)
2154a111cadSNamhyung Kim return a->self.size < b->self.size;
2164a111cadSNamhyung Kim return strcmp(a->self.type_name, b->self.type_name) < 0;
2174a111cadSNamhyung Kim }
2184a111cadSNamhyung Kim
2194a111cadSNamhyung Kim /* Recursively add new members for struct/union */
__add_member_cb(Dwarf_Die * die,void * arg)2204a111cadSNamhyung Kim static int __add_member_cb(Dwarf_Die *die, void *arg)
2214a111cadSNamhyung Kim {
2224a111cadSNamhyung Kim struct annotated_member *parent = arg;
2234a111cadSNamhyung Kim struct annotated_member *member;
2244a111cadSNamhyung Kim Dwarf_Die member_type, die_mem;
2258b1042c4SNamhyung Kim Dwarf_Word size, loc, bit_size = 0;
2264a111cadSNamhyung Kim Dwarf_Attribute attr;
2274a111cadSNamhyung Kim struct strbuf sb;
2284a111cadSNamhyung Kim int tag;
2294a111cadSNamhyung Kim
2304a111cadSNamhyung Kim if (dwarf_tag(die) != DW_TAG_member)
2314a111cadSNamhyung Kim return DIE_FIND_CB_SIBLING;
2324a111cadSNamhyung Kim
2334a111cadSNamhyung Kim member = zalloc(sizeof(*member));
2344a111cadSNamhyung Kim if (member == NULL)
2354a111cadSNamhyung Kim return DIE_FIND_CB_END;
2364a111cadSNamhyung Kim
2374a111cadSNamhyung Kim strbuf_init(&sb, 32);
2384a111cadSNamhyung Kim die_get_typename(die, &sb);
2394a111cadSNamhyung Kim
24090d78e7bSNamhyung Kim __die_get_real_type(die, &member_type);
24190d78e7bSNamhyung Kim if (dwarf_tag(&member_type) == DW_TAG_typedef)
24290d78e7bSNamhyung Kim die_get_real_type(&member_type, &die_mem);
24390d78e7bSNamhyung Kim else
24490d78e7bSNamhyung Kim die_mem = member_type;
24590d78e7bSNamhyung Kim
24690d78e7bSNamhyung Kim if (dwarf_aggregate_size(&die_mem, &size) < 0)
2474a111cadSNamhyung Kim size = 0;
2484a111cadSNamhyung Kim
2498b1042c4SNamhyung Kim if (dwarf_attr_integrate(die, DW_AT_data_member_location, &attr))
2504a111cadSNamhyung Kim dwarf_formudata(&attr, &loc);
2518b1042c4SNamhyung Kim else {
2528b1042c4SNamhyung Kim /* bitfield member */
2538b1042c4SNamhyung Kim if (dwarf_attr_integrate(die, DW_AT_data_bit_offset, &attr) &&
2548b1042c4SNamhyung Kim dwarf_formudata(&attr, &loc) == 0)
2558b1042c4SNamhyung Kim loc /= 8;
2568b1042c4SNamhyung Kim else
2578b1042c4SNamhyung Kim loc = 0;
2588b1042c4SNamhyung Kim
2598b1042c4SNamhyung Kim if (dwarf_attr_integrate(die, DW_AT_bit_size, &attr) &&
2608b1042c4SNamhyung Kim dwarf_formudata(&attr, &bit_size) == 0)
2618b1042c4SNamhyung Kim size = (bit_size + 7) / 8;
2628b1042c4SNamhyung Kim }
2634a111cadSNamhyung Kim
2644a111cadSNamhyung Kim member->type_name = strbuf_detach(&sb, NULL);
2654a111cadSNamhyung Kim /* member->var_name can be NULL */
2668b1042c4SNamhyung Kim if (dwarf_diename(die)) {
2678b1042c4SNamhyung Kim if (bit_size) {
2688b1042c4SNamhyung Kim if (asprintf(&member->var_name, "%s:%ld",
2698b1042c4SNamhyung Kim dwarf_diename(die), (long)bit_size) < 0)
2708b1042c4SNamhyung Kim member->var_name = NULL;
2718b1042c4SNamhyung Kim } else {
2724a111cadSNamhyung Kim member->var_name = strdup(dwarf_diename(die));
2738b1042c4SNamhyung Kim }
2748b1042c4SNamhyung Kim
2758b1042c4SNamhyung Kim if (member->var_name == NULL) {
2768b1042c4SNamhyung Kim free(member);
2778b1042c4SNamhyung Kim return DIE_FIND_CB_END;
2788b1042c4SNamhyung Kim }
2798b1042c4SNamhyung Kim }
2804a111cadSNamhyung Kim member->size = size;
2814a111cadSNamhyung Kim member->offset = loc + parent->offset;
2824a111cadSNamhyung Kim INIT_LIST_HEAD(&member->children);
2834a111cadSNamhyung Kim list_add_tail(&member->node, &parent->children);
2844a111cadSNamhyung Kim
28590d78e7bSNamhyung Kim tag = dwarf_tag(&die_mem);
2864a111cadSNamhyung Kim switch (tag) {
2874a111cadSNamhyung Kim case DW_TAG_structure_type:
2884a111cadSNamhyung Kim case DW_TAG_union_type:
28990d78e7bSNamhyung Kim die_find_child(&die_mem, __add_member_cb, member, &die_mem);
2904a111cadSNamhyung Kim break;
2914a111cadSNamhyung Kim default:
2924a111cadSNamhyung Kim break;
2934a111cadSNamhyung Kim }
2944a111cadSNamhyung Kim return DIE_FIND_CB_SIBLING;
2954a111cadSNamhyung Kim }
2964a111cadSNamhyung Kim
add_member_types(struct annotated_data_type * parent,Dwarf_Die * type)2974a111cadSNamhyung Kim static void add_member_types(struct annotated_data_type *parent, Dwarf_Die *type)
2984a111cadSNamhyung Kim {
2994a111cadSNamhyung Kim Dwarf_Die die_mem;
3004a111cadSNamhyung Kim
3014a111cadSNamhyung Kim die_find_child(type, __add_member_cb, &parent->self, &die_mem);
3024a111cadSNamhyung Kim }
3034a111cadSNamhyung Kim
delete_members(struct annotated_member * member)3044a111cadSNamhyung Kim static void delete_members(struct annotated_member *member)
3054a111cadSNamhyung Kim {
3064a111cadSNamhyung Kim struct annotated_member *child, *tmp;
3074a111cadSNamhyung Kim
3084a111cadSNamhyung Kim list_for_each_entry_safe(child, tmp, &member->children, node) {
3094a111cadSNamhyung Kim list_del(&child->node);
3104a111cadSNamhyung Kim delete_members(child);
31169fb6eabSArnaldo Carvalho de Melo zfree(&child->type_name);
31269fb6eabSArnaldo Carvalho de Melo zfree(&child->var_name);
3134a111cadSNamhyung Kim free(child);
3144a111cadSNamhyung Kim }
315fc044c53SNamhyung Kim }
316fc044c53SNamhyung Kim
fill_member_name(char * buf,size_t sz,struct annotated_member * m,int offset,bool first)317*ce2289adSNamhyung Kim static int fill_member_name(char *buf, size_t sz, struct annotated_member *m,
318*ce2289adSNamhyung Kim int offset, bool first)
319*ce2289adSNamhyung Kim {
320*ce2289adSNamhyung Kim struct annotated_member *child;
321*ce2289adSNamhyung Kim
322*ce2289adSNamhyung Kim if (list_empty(&m->children))
323*ce2289adSNamhyung Kim return 0;
324*ce2289adSNamhyung Kim
325*ce2289adSNamhyung Kim list_for_each_entry(child, &m->children, node) {
326*ce2289adSNamhyung Kim int len;
327*ce2289adSNamhyung Kim
328*ce2289adSNamhyung Kim if (offset < child->offset || offset >= child->offset + child->size)
329*ce2289adSNamhyung Kim continue;
330*ce2289adSNamhyung Kim
331*ce2289adSNamhyung Kim /* It can have anonymous struct/union members */
332*ce2289adSNamhyung Kim if (child->var_name) {
333*ce2289adSNamhyung Kim len = scnprintf(buf, sz, "%s%s",
334*ce2289adSNamhyung Kim first ? "" : ".", child->var_name);
335*ce2289adSNamhyung Kim first = false;
336*ce2289adSNamhyung Kim } else {
337*ce2289adSNamhyung Kim len = 0;
338*ce2289adSNamhyung Kim }
339*ce2289adSNamhyung Kim
340*ce2289adSNamhyung Kim return fill_member_name(buf + len, sz - len, child, offset, first) + len;
341*ce2289adSNamhyung Kim }
342*ce2289adSNamhyung Kim return 0;
343*ce2289adSNamhyung Kim }
344*ce2289adSNamhyung Kim
annotated_data_type__get_member_name(struct annotated_data_type * adt,char * buf,size_t sz,int member_offset)345*ce2289adSNamhyung Kim int annotated_data_type__get_member_name(struct annotated_data_type *adt,
346*ce2289adSNamhyung Kim char *buf, size_t sz, int member_offset)
347*ce2289adSNamhyung Kim {
348*ce2289adSNamhyung Kim return fill_member_name(buf, sz, &adt->self, member_offset, /*first=*/true);
349*ce2289adSNamhyung Kim }
350*ce2289adSNamhyung Kim
dso__findnew_data_type(struct dso * dso,Dwarf_Die * type_die)351fc044c53SNamhyung Kim static struct annotated_data_type *dso__findnew_data_type(struct dso *dso,
352fc044c53SNamhyung Kim Dwarf_Die *type_die)
353fc044c53SNamhyung Kim {
354fc044c53SNamhyung Kim struct annotated_data_type *result = NULL;
355fc044c53SNamhyung Kim struct annotated_data_type key;
356fc044c53SNamhyung Kim struct rb_node *node;
357fc044c53SNamhyung Kim struct strbuf sb;
358fc044c53SNamhyung Kim char *type_name;
359fc044c53SNamhyung Kim Dwarf_Word size;
360fc044c53SNamhyung Kim
361fc044c53SNamhyung Kim strbuf_init(&sb, 32);
362fc044c53SNamhyung Kim if (die_get_typename_from_type(type_die, &sb) < 0)
363fc044c53SNamhyung Kim strbuf_add(&sb, "(unknown type)", 14);
364fc044c53SNamhyung Kim type_name = strbuf_detach(&sb, NULL);
36590d78e7bSNamhyung Kim
36690d78e7bSNamhyung Kim if (dwarf_tag(type_die) == DW_TAG_typedef)
36790d78e7bSNamhyung Kim die_get_real_type(type_die, type_die);
36890d78e7bSNamhyung Kim
369fc044c53SNamhyung Kim dwarf_aggregate_size(type_die, &size);
370fc044c53SNamhyung Kim
371fc044c53SNamhyung Kim /* Check existing nodes in dso->data_types tree */
3724a111cadSNamhyung Kim key.self.type_name = type_name;
3734a111cadSNamhyung Kim key.self.size = size;
374ee756ef7SIan Rogers node = rb_find(&key, dso__data_types(dso), data_type_cmp);
375fc044c53SNamhyung Kim if (node) {
376fc044c53SNamhyung Kim result = rb_entry(node, struct annotated_data_type, node);
377fc044c53SNamhyung Kim free(type_name);
378fc044c53SNamhyung Kim return result;
379fc044c53SNamhyung Kim }
380fc044c53SNamhyung Kim
381fc044c53SNamhyung Kim /* If not, add a new one */
382fc044c53SNamhyung Kim result = zalloc(sizeof(*result));
383fc044c53SNamhyung Kim if (result == NULL) {
384fc044c53SNamhyung Kim free(type_name);
385fc044c53SNamhyung Kim return NULL;
386fc044c53SNamhyung Kim }
387fc044c53SNamhyung Kim
3884a111cadSNamhyung Kim result->self.type_name = type_name;
3894a111cadSNamhyung Kim result->self.size = size;
3904a111cadSNamhyung Kim INIT_LIST_HEAD(&result->self.children);
3914a111cadSNamhyung Kim
392263925bfSNamhyung Kim if (symbol_conf.annotate_data_member)
3934a111cadSNamhyung Kim add_member_types(result, type_die);
394fc044c53SNamhyung Kim
395ee756ef7SIan Rogers rb_add(&result->node, dso__data_types(dso), data_type_less);
396fc044c53SNamhyung Kim return result;
397fc044c53SNamhyung Kim }
398fc044c53SNamhyung Kim
find_cu_die(struct debuginfo * di,u64 pc,Dwarf_Die * cu_die)399b9c87f53SNamhyung Kim static bool find_cu_die(struct debuginfo *di, u64 pc, Dwarf_Die *cu_die)
400b9c87f53SNamhyung Kim {
401b9c87f53SNamhyung Kim Dwarf_Off off, next_off;
402b9c87f53SNamhyung Kim size_t header_size;
403b9c87f53SNamhyung Kim
404b9c87f53SNamhyung Kim if (dwarf_addrdie(di->dbg, pc, cu_die) != NULL)
405b9c87f53SNamhyung Kim return cu_die;
406b9c87f53SNamhyung Kim
407b9c87f53SNamhyung Kim /*
408b9c87f53SNamhyung Kim * There are some kernels don't have full aranges and contain only a few
409b9c87f53SNamhyung Kim * aranges entries. Fallback to iterate all CU entries in .debug_info
410b9c87f53SNamhyung Kim * in case it's missing.
411b9c87f53SNamhyung Kim */
412b9c87f53SNamhyung Kim off = 0;
413b9c87f53SNamhyung Kim while (dwarf_nextcu(di->dbg, off, &next_off, &header_size,
414b9c87f53SNamhyung Kim NULL, NULL, NULL) == 0) {
415b9c87f53SNamhyung Kim if (dwarf_offdie(di->dbg, off + header_size, cu_die) &&
416b9c87f53SNamhyung Kim dwarf_haspc(cu_die, pc))
417b9c87f53SNamhyung Kim return true;
418b9c87f53SNamhyung Kim
419b9c87f53SNamhyung Kim off = next_off;
420b9c87f53SNamhyung Kim }
421b9c87f53SNamhyung Kim return false;
422b9c87f53SNamhyung Kim }
423b9c87f53SNamhyung Kim
424976862f8SNamhyung Kim enum type_match_result {
425976862f8SNamhyung Kim PERF_TMR_UNKNOWN = 0,
426976862f8SNamhyung Kim PERF_TMR_OK,
427976862f8SNamhyung Kim PERF_TMR_NO_TYPE,
428976862f8SNamhyung Kim PERF_TMR_NO_POINTER,
429976862f8SNamhyung Kim PERF_TMR_NO_SIZE,
430976862f8SNamhyung Kim PERF_TMR_BAD_OFFSET,
43169e2c784SNamhyung Kim PERF_TMR_BAIL_OUT,
432976862f8SNamhyung Kim };
433976862f8SNamhyung Kim
match_result_str(enum type_match_result tmr)434653185d8SNamhyung Kim static const char *match_result_str(enum type_match_result tmr)
435653185d8SNamhyung Kim {
436653185d8SNamhyung Kim switch (tmr) {
437653185d8SNamhyung Kim case PERF_TMR_OK:
438653185d8SNamhyung Kim return "Good!";
439653185d8SNamhyung Kim case PERF_TMR_NO_TYPE:
440653185d8SNamhyung Kim return "no type information";
441653185d8SNamhyung Kim case PERF_TMR_NO_POINTER:
442653185d8SNamhyung Kim return "no/void pointer";
443653185d8SNamhyung Kim case PERF_TMR_NO_SIZE:
444653185d8SNamhyung Kim return "type size is unknown";
445653185d8SNamhyung Kim case PERF_TMR_BAD_OFFSET:
446653185d8SNamhyung Kim return "offset bigger than size";
447653185d8SNamhyung Kim case PERF_TMR_UNKNOWN:
44869e2c784SNamhyung Kim case PERF_TMR_BAIL_OUT:
449653185d8SNamhyung Kim default:
450653185d8SNamhyung Kim return "invalid state";
451653185d8SNamhyung Kim }
452653185d8SNamhyung Kim }
453653185d8SNamhyung Kim
is_pointer_type(Dwarf_Die * type_die)45498d1f1dcSNamhyung Kim static bool is_pointer_type(Dwarf_Die *type_die)
45598d1f1dcSNamhyung Kim {
45698d1f1dcSNamhyung Kim int tag = dwarf_tag(type_die);
45798d1f1dcSNamhyung Kim
45898d1f1dcSNamhyung Kim return tag == DW_TAG_pointer_type || tag == DW_TAG_array_type;
45998d1f1dcSNamhyung Kim }
46098d1f1dcSNamhyung Kim
is_compound_type(Dwarf_Die * type_die)4614a32a972SNamhyung Kim static bool is_compound_type(Dwarf_Die *type_die)
4624a32a972SNamhyung Kim {
4634a32a972SNamhyung Kim int tag = dwarf_tag(type_die);
4644a32a972SNamhyung Kim
4654a32a972SNamhyung Kim return tag == DW_TAG_structure_type || tag == DW_TAG_union_type;
4664a32a972SNamhyung Kim }
4674a32a972SNamhyung Kim
468c663451fSNamhyung Kim /* returns if Type B has better information than Type A */
is_better_type(Dwarf_Die * type_a,Dwarf_Die * type_b)469c663451fSNamhyung Kim static bool is_better_type(Dwarf_Die *type_a, Dwarf_Die *type_b)
470c663451fSNamhyung Kim {
471c663451fSNamhyung Kim Dwarf_Word size_a, size_b;
472c663451fSNamhyung Kim Dwarf_Die die_a, die_b;
473c663451fSNamhyung Kim
474c663451fSNamhyung Kim /* pointer type is preferred */
475c663451fSNamhyung Kim if (is_pointer_type(type_a) != is_pointer_type(type_b))
476c663451fSNamhyung Kim return is_pointer_type(type_b);
477c663451fSNamhyung Kim
478c663451fSNamhyung Kim if (is_pointer_type(type_b)) {
479c663451fSNamhyung Kim /*
480c663451fSNamhyung Kim * We want to compare the target type, but 'void *' can fail to
481c663451fSNamhyung Kim * get the target type.
482c663451fSNamhyung Kim */
483c663451fSNamhyung Kim if (die_get_real_type(type_a, &die_a) == NULL)
484c663451fSNamhyung Kim return true;
485c663451fSNamhyung Kim if (die_get_real_type(type_b, &die_b) == NULL)
486c663451fSNamhyung Kim return false;
487c663451fSNamhyung Kim
488c663451fSNamhyung Kim type_a = &die_a;
489c663451fSNamhyung Kim type_b = &die_b;
490c663451fSNamhyung Kim }
491c663451fSNamhyung Kim
492c663451fSNamhyung Kim /* bigger type is preferred */
493c663451fSNamhyung Kim if (dwarf_aggregate_size(type_a, &size_a) < 0 ||
494c663451fSNamhyung Kim dwarf_aggregate_size(type_b, &size_b) < 0)
495c663451fSNamhyung Kim return false;
496c663451fSNamhyung Kim
4974a32a972SNamhyung Kim if (size_a != size_b)
498c663451fSNamhyung Kim return size_a < size_b;
4994a32a972SNamhyung Kim
5004a32a972SNamhyung Kim /* struct or union is preferred */
5014a32a972SNamhyung Kim if (is_compound_type(type_a) != is_compound_type(type_b))
5024a32a972SNamhyung Kim return is_compound_type(type_b);
5034a32a972SNamhyung Kim
5044a32a972SNamhyung Kim /* typedef is preferred */
5054a32a972SNamhyung Kim if (dwarf_tag(type_b) == DW_TAG_typedef)
5064a32a972SNamhyung Kim return true;
5074a32a972SNamhyung Kim
5084a32a972SNamhyung Kim return false;
509c663451fSNamhyung Kim }
510c663451fSNamhyung Kim
511b9c87f53SNamhyung Kim /* The type info will be saved in @type_die */
check_variable(struct data_loc_info * dloc,Dwarf_Die * var_die,Dwarf_Die * type_die,int reg,int offset,bool is_fbreg)512976862f8SNamhyung Kim static enum type_match_result check_variable(struct data_loc_info *dloc,
513976862f8SNamhyung Kim Dwarf_Die *var_die,
514976862f8SNamhyung Kim Dwarf_Die *type_die, int reg,
515976862f8SNamhyung Kim int offset, bool is_fbreg)
516b9c87f53SNamhyung Kim {
517b9c87f53SNamhyung Kim Dwarf_Word size;
51898d1f1dcSNamhyung Kim bool needs_pointer = true;
51990d78e7bSNamhyung Kim Dwarf_Die sized_type;
520a5a00497SNamhyung Kim
521a5a00497SNamhyung Kim if (reg == DWARF_REG_PC)
52298d1f1dcSNamhyung Kim needs_pointer = false;
523a5a00497SNamhyung Kim else if (reg == dloc->fbreg || is_fbreg)
52498d1f1dcSNamhyung Kim needs_pointer = false;
525a5a00497SNamhyung Kim else if (arch__is(dloc->arch, "x86") && reg == X86_REG_SP)
52698d1f1dcSNamhyung Kim needs_pointer = false;
527b9c87f53SNamhyung Kim
528b9c87f53SNamhyung Kim /* Get the type of the variable */
529023aceecSNamhyung Kim if (__die_get_real_type(var_die, type_die) == NULL)
530976862f8SNamhyung Kim return PERF_TMR_NO_TYPE;
531b9c87f53SNamhyung Kim
532b9c87f53SNamhyung Kim /*
53383bfa06dSNamhyung Kim * Usually it expects a pointer type for a memory access.
53483bfa06dSNamhyung Kim * Convert to a real type it points to. But global variables
535bc10db8eSNamhyung Kim * and local variables are accessed directly without a pointer.
536b9c87f53SNamhyung Kim */
53798d1f1dcSNamhyung Kim if (needs_pointer) {
53898d1f1dcSNamhyung Kim if (!is_pointer_type(type_die) ||
539023aceecSNamhyung Kim __die_get_real_type(type_die, type_die) == NULL)
540976862f8SNamhyung Kim return PERF_TMR_NO_POINTER;
541b9c87f53SNamhyung Kim }
542b9c87f53SNamhyung Kim
54390d78e7bSNamhyung Kim if (dwarf_tag(type_die) == DW_TAG_typedef)
54490d78e7bSNamhyung Kim die_get_real_type(type_die, &sized_type);
54590d78e7bSNamhyung Kim else
54690d78e7bSNamhyung Kim sized_type = *type_die;
54790d78e7bSNamhyung Kim
548b9c87f53SNamhyung Kim /* Get the size of the actual type */
549023aceecSNamhyung Kim if (dwarf_aggregate_size(&sized_type, &size) < 0)
550976862f8SNamhyung Kim return PERF_TMR_NO_SIZE;
551b9c87f53SNamhyung Kim
552b9c87f53SNamhyung Kim /* Minimal sanity check */
553023aceecSNamhyung Kim if ((unsigned)offset >= size)
554976862f8SNamhyung Kim return PERF_TMR_BAD_OFFSET;
555b9c87f53SNamhyung Kim
556976862f8SNamhyung Kim return PERF_TMR_OK;
557b9c87f53SNamhyung Kim }
558b9c87f53SNamhyung Kim
find_stack_state(struct type_state * state,int offset)559782959acSAthira Rajeev struct type_state_stack *find_stack_state(struct type_state *state,
56006b2ce75SNamhyung Kim int offset)
56106b2ce75SNamhyung Kim {
56206b2ce75SNamhyung Kim struct type_state_stack *stack;
56306b2ce75SNamhyung Kim
56406b2ce75SNamhyung Kim list_for_each_entry(stack, &state->stack_vars, list) {
56506b2ce75SNamhyung Kim if (offset == stack->offset)
56606b2ce75SNamhyung Kim return stack;
56706b2ce75SNamhyung Kim
56806b2ce75SNamhyung Kim if (stack->compound && stack->offset < offset &&
56906b2ce75SNamhyung Kim offset < stack->offset + stack->size)
57006b2ce75SNamhyung Kim return stack;
57106b2ce75SNamhyung Kim }
57206b2ce75SNamhyung Kim return NULL;
57306b2ce75SNamhyung Kim }
57406b2ce75SNamhyung Kim
set_stack_state(struct type_state_stack * stack,int offset,u8 kind,Dwarf_Die * type_die)575782959acSAthira Rajeev void set_stack_state(struct type_state_stack *stack, int offset, u8 kind,
57606b2ce75SNamhyung Kim Dwarf_Die *type_die)
57706b2ce75SNamhyung Kim {
57806b2ce75SNamhyung Kim int tag;
57906b2ce75SNamhyung Kim Dwarf_Word size;
58006b2ce75SNamhyung Kim
58106b2ce75SNamhyung Kim if (dwarf_aggregate_size(type_die, &size) < 0)
58206b2ce75SNamhyung Kim size = 0;
58306b2ce75SNamhyung Kim
58406b2ce75SNamhyung Kim tag = dwarf_tag(type_die);
58506b2ce75SNamhyung Kim
58606b2ce75SNamhyung Kim stack->type = *type_die;
58706b2ce75SNamhyung Kim stack->size = size;
58806b2ce75SNamhyung Kim stack->offset = offset;
589f5b09592SNamhyung Kim stack->kind = kind;
59006b2ce75SNamhyung Kim
59106b2ce75SNamhyung Kim switch (tag) {
59206b2ce75SNamhyung Kim case DW_TAG_structure_type:
59306b2ce75SNamhyung Kim case DW_TAG_union_type:
594eb9190afSNamhyung Kim stack->compound = (kind != TSR_KIND_POINTER);
59506b2ce75SNamhyung Kim break;
59606b2ce75SNamhyung Kim default:
59706b2ce75SNamhyung Kim stack->compound = false;
59806b2ce75SNamhyung Kim break;
59906b2ce75SNamhyung Kim }
60006b2ce75SNamhyung Kim }
60106b2ce75SNamhyung Kim
findnew_stack_state(struct type_state * state,int offset,u8 kind,Dwarf_Die * type_die)602782959acSAthira Rajeev struct type_state_stack *findnew_stack_state(struct type_state *state,
603f5b09592SNamhyung Kim int offset, u8 kind,
604f5b09592SNamhyung Kim Dwarf_Die *type_die)
60506b2ce75SNamhyung Kim {
60606b2ce75SNamhyung Kim struct type_state_stack *stack = find_stack_state(state, offset);
60706b2ce75SNamhyung Kim
60806b2ce75SNamhyung Kim if (stack) {
609f5b09592SNamhyung Kim set_stack_state(stack, offset, kind, type_die);
61006b2ce75SNamhyung Kim return stack;
61106b2ce75SNamhyung Kim }
61206b2ce75SNamhyung Kim
61306b2ce75SNamhyung Kim stack = malloc(sizeof(*stack));
61406b2ce75SNamhyung Kim if (stack) {
615f5b09592SNamhyung Kim set_stack_state(stack, offset, kind, type_die);
61606b2ce75SNamhyung Kim list_add(&stack->list, &state->stack_vars);
61706b2ce75SNamhyung Kim }
61806b2ce75SNamhyung Kim return stack;
61906b2ce75SNamhyung Kim }
62006b2ce75SNamhyung Kim
62155ee3d00SNamhyung Kim /* Maintain a cache for quick global variable lookup */
62255ee3d00SNamhyung Kim struct global_var_entry {
62355ee3d00SNamhyung Kim struct rb_node node;
62455ee3d00SNamhyung Kim char *name;
62555ee3d00SNamhyung Kim u64 start;
62655ee3d00SNamhyung Kim u64 end;
62755ee3d00SNamhyung Kim u64 die_offset;
62855ee3d00SNamhyung Kim };
62955ee3d00SNamhyung Kim
global_var_cmp(const void * _key,const struct rb_node * node)63055ee3d00SNamhyung Kim static int global_var_cmp(const void *_key, const struct rb_node *node)
63155ee3d00SNamhyung Kim {
63255ee3d00SNamhyung Kim const u64 addr = (uintptr_t)_key;
63355ee3d00SNamhyung Kim struct global_var_entry *gvar;
63455ee3d00SNamhyung Kim
63555ee3d00SNamhyung Kim gvar = rb_entry(node, struct global_var_entry, node);
63655ee3d00SNamhyung Kim
63755ee3d00SNamhyung Kim if (gvar->start <= addr && addr < gvar->end)
63855ee3d00SNamhyung Kim return 0;
63955ee3d00SNamhyung Kim return gvar->start > addr ? -1 : 1;
64055ee3d00SNamhyung Kim }
64155ee3d00SNamhyung Kim
global_var_less(struct rb_node * node_a,const struct rb_node * node_b)64255ee3d00SNamhyung Kim static bool global_var_less(struct rb_node *node_a, const struct rb_node *node_b)
64355ee3d00SNamhyung Kim {
64455ee3d00SNamhyung Kim struct global_var_entry *gvar_a, *gvar_b;
64555ee3d00SNamhyung Kim
64655ee3d00SNamhyung Kim gvar_a = rb_entry(node_a, struct global_var_entry, node);
64755ee3d00SNamhyung Kim gvar_b = rb_entry(node_b, struct global_var_entry, node);
64855ee3d00SNamhyung Kim
64955ee3d00SNamhyung Kim return gvar_a->start < gvar_b->start;
65055ee3d00SNamhyung Kim }
65155ee3d00SNamhyung Kim
global_var__find(struct data_loc_info * dloc,u64 addr)65255ee3d00SNamhyung Kim static struct global_var_entry *global_var__find(struct data_loc_info *dloc, u64 addr)
65355ee3d00SNamhyung Kim {
65455ee3d00SNamhyung Kim struct dso *dso = map__dso(dloc->ms->map);
65555ee3d00SNamhyung Kim struct rb_node *node;
65655ee3d00SNamhyung Kim
657ee756ef7SIan Rogers node = rb_find((void *)(uintptr_t)addr, dso__global_vars(dso), global_var_cmp);
65855ee3d00SNamhyung Kim if (node == NULL)
65955ee3d00SNamhyung Kim return NULL;
66055ee3d00SNamhyung Kim
66155ee3d00SNamhyung Kim return rb_entry(node, struct global_var_entry, node);
66255ee3d00SNamhyung Kim }
66355ee3d00SNamhyung Kim
global_var__add(struct data_loc_info * dloc,u64 addr,const char * name,Dwarf_Die * type_die)66455ee3d00SNamhyung Kim static bool global_var__add(struct data_loc_info *dloc, u64 addr,
66555ee3d00SNamhyung Kim const char *name, Dwarf_Die *type_die)
66655ee3d00SNamhyung Kim {
66755ee3d00SNamhyung Kim struct dso *dso = map__dso(dloc->ms->map);
66855ee3d00SNamhyung Kim struct global_var_entry *gvar;
66955ee3d00SNamhyung Kim Dwarf_Word size;
67055ee3d00SNamhyung Kim
67155ee3d00SNamhyung Kim if (dwarf_aggregate_size(type_die, &size) < 0)
67255ee3d00SNamhyung Kim return false;
67355ee3d00SNamhyung Kim
67455ee3d00SNamhyung Kim gvar = malloc(sizeof(*gvar));
67555ee3d00SNamhyung Kim if (gvar == NULL)
67655ee3d00SNamhyung Kim return false;
67755ee3d00SNamhyung Kim
678c1da8411SNamhyung Kim gvar->name = name ? strdup(name) : NULL;
679c1da8411SNamhyung Kim if (name && gvar->name == NULL) {
68055ee3d00SNamhyung Kim free(gvar);
68155ee3d00SNamhyung Kim return false;
68255ee3d00SNamhyung Kim }
68355ee3d00SNamhyung Kim
68455ee3d00SNamhyung Kim gvar->start = addr;
68555ee3d00SNamhyung Kim gvar->end = addr + size;
68655ee3d00SNamhyung Kim gvar->die_offset = dwarf_dieoffset(type_die);
68755ee3d00SNamhyung Kim
688ee756ef7SIan Rogers rb_add(&gvar->node, dso__global_vars(dso), global_var_less);
68955ee3d00SNamhyung Kim return true;
69055ee3d00SNamhyung Kim }
69155ee3d00SNamhyung Kim
global_var_type__tree_delete(struct rb_root * root)69255ee3d00SNamhyung Kim void global_var_type__tree_delete(struct rb_root *root)
69355ee3d00SNamhyung Kim {
69455ee3d00SNamhyung Kim struct global_var_entry *gvar;
69555ee3d00SNamhyung Kim
69655ee3d00SNamhyung Kim while (!RB_EMPTY_ROOT(root)) {
69755ee3d00SNamhyung Kim struct rb_node *node = rb_first(root);
69855ee3d00SNamhyung Kim
69955ee3d00SNamhyung Kim rb_erase(node, root);
70055ee3d00SNamhyung Kim gvar = rb_entry(node, struct global_var_entry, node);
70169fb6eabSArnaldo Carvalho de Melo zfree(&gvar->name);
70255ee3d00SNamhyung Kim free(gvar);
70355ee3d00SNamhyung Kim }
70455ee3d00SNamhyung Kim }
70555ee3d00SNamhyung Kim
get_global_var_info(struct data_loc_info * dloc,u64 addr,const char ** var_name,int * var_offset)706782959acSAthira Rajeev bool get_global_var_info(struct data_loc_info *dloc, u64 addr,
707f5b09592SNamhyung Kim const char **var_name, int *var_offset)
708f5b09592SNamhyung Kim {
709f5b09592SNamhyung Kim struct addr_location al;
710f5b09592SNamhyung Kim struct symbol *sym;
711f5b09592SNamhyung Kim u64 mem_addr;
712f5b09592SNamhyung Kim
713f5b09592SNamhyung Kim /* Kernel symbols might be relocated */
714f5b09592SNamhyung Kim mem_addr = addr + map__reloc(dloc->ms->map);
715f5b09592SNamhyung Kim
716f5b09592SNamhyung Kim addr_location__init(&al);
717f5b09592SNamhyung Kim sym = thread__find_symbol_fb(dloc->thread, dloc->cpumode,
718f5b09592SNamhyung Kim mem_addr, &al);
719f5b09592SNamhyung Kim if (sym) {
720f5b09592SNamhyung Kim *var_name = sym->name;
721f5b09592SNamhyung Kim /* Calculate type offset from the start of variable */
722f5b09592SNamhyung Kim *var_offset = mem_addr - map__unmap_ip(al.map, sym->start);
723f5b09592SNamhyung Kim } else {
724f5b09592SNamhyung Kim *var_name = NULL;
725f5b09592SNamhyung Kim }
726f5b09592SNamhyung Kim addr_location__exit(&al);
727f5b09592SNamhyung Kim if (*var_name == NULL)
728f5b09592SNamhyung Kim return false;
729f5b09592SNamhyung Kim
730f5b09592SNamhyung Kim return true;
731f5b09592SNamhyung Kim }
732f5b09592SNamhyung Kim
global_var__collect(struct data_loc_info * dloc)733c1da8411SNamhyung Kim static void global_var__collect(struct data_loc_info *dloc)
734c1da8411SNamhyung Kim {
735c1da8411SNamhyung Kim Dwarf *dwarf = dloc->di->dbg;
736c1da8411SNamhyung Kim Dwarf_Off off, next_off;
737c1da8411SNamhyung Kim Dwarf_Die cu_die, type_die;
738c1da8411SNamhyung Kim size_t header_size;
739c1da8411SNamhyung Kim
740c1da8411SNamhyung Kim /* Iterate all CU and collect global variables that have no location in a register. */
741c1da8411SNamhyung Kim off = 0;
742c1da8411SNamhyung Kim while (dwarf_nextcu(dwarf, off, &next_off, &header_size,
743c1da8411SNamhyung Kim NULL, NULL, NULL) == 0) {
744c1da8411SNamhyung Kim struct die_var_type *var_types = NULL;
745c1da8411SNamhyung Kim struct die_var_type *pos;
746c1da8411SNamhyung Kim
747c1da8411SNamhyung Kim if (dwarf_offdie(dwarf, off + header_size, &cu_die) == NULL) {
748c1da8411SNamhyung Kim off = next_off;
749c1da8411SNamhyung Kim continue;
750c1da8411SNamhyung Kim }
751c1da8411SNamhyung Kim
752c1da8411SNamhyung Kim die_collect_global_vars(&cu_die, &var_types);
753c1da8411SNamhyung Kim
754c1da8411SNamhyung Kim for (pos = var_types; pos; pos = pos->next) {
755c1da8411SNamhyung Kim const char *var_name = NULL;
756c1da8411SNamhyung Kim int var_offset = 0;
757c1da8411SNamhyung Kim
758c1da8411SNamhyung Kim if (pos->reg != -1)
759c1da8411SNamhyung Kim continue;
760c1da8411SNamhyung Kim
761c1da8411SNamhyung Kim if (!dwarf_offdie(dwarf, pos->die_off, &type_die))
762c1da8411SNamhyung Kim continue;
763c1da8411SNamhyung Kim
764c1da8411SNamhyung Kim if (!get_global_var_info(dloc, pos->addr, &var_name,
765c1da8411SNamhyung Kim &var_offset))
766c1da8411SNamhyung Kim continue;
767c1da8411SNamhyung Kim
768c1da8411SNamhyung Kim if (var_offset != 0)
769c1da8411SNamhyung Kim continue;
770c1da8411SNamhyung Kim
771c1da8411SNamhyung Kim global_var__add(dloc, pos->addr, var_name, &type_die);
772c1da8411SNamhyung Kim }
773c1da8411SNamhyung Kim
774c1da8411SNamhyung Kim delete_var_types(var_types);
775c1da8411SNamhyung Kim
776c1da8411SNamhyung Kim off = next_off;
777c1da8411SNamhyung Kim }
778c1da8411SNamhyung Kim }
779c1da8411SNamhyung Kim
get_global_var_type(Dwarf_Die * cu_die,struct data_loc_info * dloc,u64 ip,u64 var_addr,int * var_offset,Dwarf_Die * type_die)780782959acSAthira Rajeev bool get_global_var_type(Dwarf_Die *cu_die, struct data_loc_info *dloc,
7811ebb5e17SNamhyung Kim u64 ip, u64 var_addr, int *var_offset,
7821ebb5e17SNamhyung Kim Dwarf_Die *type_die)
7831ebb5e17SNamhyung Kim {
784f5b09592SNamhyung Kim u64 pc;
7851ebb5e17SNamhyung Kim int offset;
78655ee3d00SNamhyung Kim const char *var_name = NULL;
78755ee3d00SNamhyung Kim struct global_var_entry *gvar;
788c1da8411SNamhyung Kim struct dso *dso = map__dso(dloc->ms->map);
7891ebb5e17SNamhyung Kim Dwarf_Die var_die;
7901ebb5e17SNamhyung Kim
791ee756ef7SIan Rogers if (RB_EMPTY_ROOT(dso__global_vars(dso)))
792c1da8411SNamhyung Kim global_var__collect(dloc);
793c1da8411SNamhyung Kim
79455ee3d00SNamhyung Kim gvar = global_var__find(dloc, var_addr);
79555ee3d00SNamhyung Kim if (gvar) {
79655ee3d00SNamhyung Kim if (!dwarf_offdie(dloc->di->dbg, gvar->die_offset, type_die))
79755ee3d00SNamhyung Kim return false;
79855ee3d00SNamhyung Kim
79955ee3d00SNamhyung Kim *var_offset = var_addr - gvar->start;
80055ee3d00SNamhyung Kim return true;
80155ee3d00SNamhyung Kim }
80255ee3d00SNamhyung Kim
8031ebb5e17SNamhyung Kim /* Try to get the variable by address first */
8041ebb5e17SNamhyung Kim if (die_find_variable_by_addr(cu_die, var_addr, &var_die, &offset) &&
805a5a00497SNamhyung Kim check_variable(dloc, &var_die, type_die, DWARF_REG_PC, offset,
806976862f8SNamhyung Kim /*is_fbreg=*/false) == PERF_TMR_OK) {
80755ee3d00SNamhyung Kim var_name = dwarf_diename(&var_die);
8081ebb5e17SNamhyung Kim *var_offset = offset;
80955ee3d00SNamhyung Kim goto ok;
8101ebb5e17SNamhyung Kim }
8111ebb5e17SNamhyung Kim
812f5b09592SNamhyung Kim if (!get_global_var_info(dloc, var_addr, &var_name, var_offset))
8131ebb5e17SNamhyung Kim return false;
8141ebb5e17SNamhyung Kim
8151ebb5e17SNamhyung Kim pc = map__rip_2objdump(dloc->ms->map, ip);
8161ebb5e17SNamhyung Kim
8171ebb5e17SNamhyung Kim /* Try to get the name of global variable */
8181ebb5e17SNamhyung Kim if (die_find_variable_at(cu_die, var_name, pc, &var_die) &&
819a5a00497SNamhyung Kim check_variable(dloc, &var_die, type_die, DWARF_REG_PC, *var_offset,
820976862f8SNamhyung Kim /*is_fbreg=*/false) == PERF_TMR_OK)
82155ee3d00SNamhyung Kim goto ok;
8221ebb5e17SNamhyung Kim
8231ebb5e17SNamhyung Kim return false;
82455ee3d00SNamhyung Kim
82555ee3d00SNamhyung Kim ok:
82655ee3d00SNamhyung Kim /* The address should point to the start of the variable */
82755ee3d00SNamhyung Kim global_var__add(dloc, var_addr - *var_offset, var_name, type_die);
82855ee3d00SNamhyung Kim return true;
8291ebb5e17SNamhyung Kim }
8301ebb5e17SNamhyung Kim
die_is_same(Dwarf_Die * die_a,Dwarf_Die * die_b)8311cfd01ebSNamhyung Kim static bool die_is_same(Dwarf_Die *die_a, Dwarf_Die *die_b)
8321cfd01ebSNamhyung Kim {
8331cfd01ebSNamhyung Kim return (die_a->cu == die_b->cu) && (die_a->addr == die_b->addr);
8341cfd01ebSNamhyung Kim }
8351cfd01ebSNamhyung Kim
83606b2ce75SNamhyung Kim /**
83706b2ce75SNamhyung Kim * update_var_state - Update type state using given variables
83806b2ce75SNamhyung Kim * @state: type state table
83906b2ce75SNamhyung Kim * @dloc: data location info
84006b2ce75SNamhyung Kim * @addr: instruction address to match with variable
84106b2ce75SNamhyung Kim * @insn_offset: instruction offset (for debug)
84206b2ce75SNamhyung Kim * @var_types: list of variables with type info
84306b2ce75SNamhyung Kim *
84406b2ce75SNamhyung Kim * This function fills the @state table using @var_types info. Each variable
84506b2ce75SNamhyung Kim * is used only at the given location and updates an entry in the table.
84606b2ce75SNamhyung Kim */
update_var_state(struct type_state * state,struct data_loc_info * dloc,u64 addr,u64 insn_offset,struct die_var_type * var_types)847eb8a55e0SNamhyung Kim static void update_var_state(struct type_state *state, struct data_loc_info *dloc,
84806b2ce75SNamhyung Kim u64 addr, u64 insn_offset, struct die_var_type *var_types)
84906b2ce75SNamhyung Kim {
85006b2ce75SNamhyung Kim Dwarf_Die mem_die;
85106b2ce75SNamhyung Kim struct die_var_type *var;
85206b2ce75SNamhyung Kim int fbreg = dloc->fbreg;
85306b2ce75SNamhyung Kim int fb_offset = 0;
85406b2ce75SNamhyung Kim
85506b2ce75SNamhyung Kim if (dloc->fb_cfa) {
85606b2ce75SNamhyung Kim if (die_get_cfa(dloc->di->dbg, addr, &fbreg, &fb_offset) < 0)
85706b2ce75SNamhyung Kim fbreg = -1;
85806b2ce75SNamhyung Kim }
85906b2ce75SNamhyung Kim
86006b2ce75SNamhyung Kim for (var = var_types; var != NULL; var = var->next) {
86106b2ce75SNamhyung Kim if (var->addr != addr)
86206b2ce75SNamhyung Kim continue;
86306b2ce75SNamhyung Kim /* Get the type DIE using the offset */
86406b2ce75SNamhyung Kim if (!dwarf_offdie(dloc->di->dbg, var->die_off, &mem_die))
86506b2ce75SNamhyung Kim continue;
86606b2ce75SNamhyung Kim
867f4dc5a33SNamhyung Kim if (var->reg == DWARF_REG_FB || var->reg == fbreg || var->reg == state->stack_reg) {
868c663451fSNamhyung Kim int offset = var->offset;
869c663451fSNamhyung Kim struct type_state_stack *stack;
870c663451fSNamhyung Kim
871c663451fSNamhyung Kim if (var->reg != DWARF_REG_FB)
872c663451fSNamhyung Kim offset -= fb_offset;
873c663451fSNamhyung Kim
874c663451fSNamhyung Kim stack = find_stack_state(state, offset);
875c663451fSNamhyung Kim if (stack && stack->kind == TSR_KIND_TYPE &&
876c663451fSNamhyung Kim !is_better_type(&stack->type, &mem_die))
877c663451fSNamhyung Kim continue;
878c663451fSNamhyung Kim
879c663451fSNamhyung Kim findnew_stack_state(state, offset, TSR_KIND_TYPE,
880f5b09592SNamhyung Kim &mem_die);
88106b2ce75SNamhyung Kim
882f4dc5a33SNamhyung Kim if (var->reg == state->stack_reg) {
883f4dc5a33SNamhyung Kim pr_debug_dtp("var [%"PRIx64"] %#x(reg%d)",
884f4dc5a33SNamhyung Kim insn_offset, offset, state->stack_reg);
885f4dc5a33SNamhyung Kim } else {
8864f903455SNamhyung Kim pr_debug_dtp("var [%"PRIx64"] -%#x(stack)",
887c663451fSNamhyung Kim insn_offset, -offset);
888f4dc5a33SNamhyung Kim }
889f5b09592SNamhyung Kim pr_debug_type_name(&mem_die, TSR_KIND_TYPE);
89006b2ce75SNamhyung Kim } else if (has_reg_type(state, var->reg) && var->offset == 0) {
89106b2ce75SNamhyung Kim struct type_state_reg *reg;
8921cfd01ebSNamhyung Kim Dwarf_Die orig_type;
89306b2ce75SNamhyung Kim
89406b2ce75SNamhyung Kim reg = &state->regs[var->reg];
895c663451fSNamhyung Kim
896c663451fSNamhyung Kim if (reg->ok && reg->kind == TSR_KIND_TYPE &&
897c663451fSNamhyung Kim !is_better_type(®->type, &mem_die))
898c663451fSNamhyung Kim continue;
899c663451fSNamhyung Kim
9001cfd01ebSNamhyung Kim orig_type = reg->type;
9011cfd01ebSNamhyung Kim
90206b2ce75SNamhyung Kim reg->type = mem_die;
903f5b09592SNamhyung Kim reg->kind = TSR_KIND_TYPE;
90406b2ce75SNamhyung Kim reg->ok = true;
90506b2ce75SNamhyung Kim
9064f903455SNamhyung Kim pr_debug_dtp("var [%"PRIx64"] reg%d",
90706b2ce75SNamhyung Kim insn_offset, var->reg);
908f5b09592SNamhyung Kim pr_debug_type_name(&mem_die, TSR_KIND_TYPE);
9091cfd01ebSNamhyung Kim
9101cfd01ebSNamhyung Kim /*
9111cfd01ebSNamhyung Kim * If this register is directly copied from another and it gets a
9121cfd01ebSNamhyung Kim * better type, also update the type of the source register. This
9131cfd01ebSNamhyung Kim * is usually the case of container_of() macro with offset of 0.
9141cfd01ebSNamhyung Kim */
9151cfd01ebSNamhyung Kim if (has_reg_type(state, reg->copied_from)) {
9161cfd01ebSNamhyung Kim struct type_state_reg *copy_reg;
9171cfd01ebSNamhyung Kim
9181cfd01ebSNamhyung Kim copy_reg = &state->regs[reg->copied_from];
9191cfd01ebSNamhyung Kim
9201cfd01ebSNamhyung Kim /* TODO: check if type is compatible or embedded */
9211cfd01ebSNamhyung Kim if (!copy_reg->ok || (copy_reg->kind != TSR_KIND_TYPE) ||
9221cfd01ebSNamhyung Kim !die_is_same(©_reg->type, &orig_type) ||
9231cfd01ebSNamhyung Kim !is_better_type(©_reg->type, &mem_die))
9241cfd01ebSNamhyung Kim continue;
9251cfd01ebSNamhyung Kim
9261cfd01ebSNamhyung Kim copy_reg->type = mem_die;
9271cfd01ebSNamhyung Kim
9281cfd01ebSNamhyung Kim pr_debug_dtp("var [%"PRIx64"] copyback reg%d",
9291cfd01ebSNamhyung Kim insn_offset, reg->copied_from);
9301cfd01ebSNamhyung Kim pr_debug_type_name(&mem_die, TSR_KIND_TYPE);
9311cfd01ebSNamhyung Kim }
93206b2ce75SNamhyung Kim }
93306b2ce75SNamhyung Kim }
93406b2ce75SNamhyung Kim }
93506b2ce75SNamhyung Kim
9360a41e5d6SNamhyung Kim /**
9370a41e5d6SNamhyung Kim * update_insn_state - Update type state for an instruction
9380a41e5d6SNamhyung Kim * @state: type state table
9390a41e5d6SNamhyung Kim * @dloc: data location info
9400a41e5d6SNamhyung Kim * @cu_die: compile unit debug entry
9410a41e5d6SNamhyung Kim * @dl: disasm line for the instruction
9420a41e5d6SNamhyung Kim *
9430a41e5d6SNamhyung Kim * This function updates the @state table for the target operand of the
9440a41e5d6SNamhyung Kim * instruction at @dl if it transfers the type like MOV on x86. Since it
9450a41e5d6SNamhyung Kim * tracks the type, it won't care about the values like in arithmetic
9460a41e5d6SNamhyung Kim * instructions like ADD/SUB/MUL/DIV and INC/DEC.
9470a41e5d6SNamhyung Kim *
9480a41e5d6SNamhyung Kim * Note that ops->reg2 is only available when both mem_ref and multi_regs
9490a41e5d6SNamhyung Kim * are true.
9500a41e5d6SNamhyung Kim */
update_insn_state(struct type_state * state,struct data_loc_info * dloc,Dwarf_Die * cu_die,struct disasm_line * dl)951eb8a55e0SNamhyung Kim static void update_insn_state(struct type_state *state, struct data_loc_info *dloc,
9520a41e5d6SNamhyung Kim Dwarf_Die *cu_die, struct disasm_line *dl)
9534f903455SNamhyung Kim {
954782959acSAthira Rajeev if (dloc->arch->update_insn_state)
955782959acSAthira Rajeev dloc->arch->update_insn_state(state, dloc, cu_die, dl);
9564f903455SNamhyung Kim }
9574f903455SNamhyung Kim
958eb8a55e0SNamhyung Kim /*
959eb8a55e0SNamhyung Kim * Prepend this_blocks (from the outer scope) to full_blocks, removing
960eb8a55e0SNamhyung Kim * duplicate disasm line.
961eb8a55e0SNamhyung Kim */
prepend_basic_blocks(struct list_head * this_blocks,struct list_head * full_blocks)962eb8a55e0SNamhyung Kim static void prepend_basic_blocks(struct list_head *this_blocks,
963eb8a55e0SNamhyung Kim struct list_head *full_blocks)
964eb8a55e0SNamhyung Kim {
965eb8a55e0SNamhyung Kim struct annotated_basic_block *first_bb, *last_bb;
966eb8a55e0SNamhyung Kim
967eb8a55e0SNamhyung Kim last_bb = list_last_entry(this_blocks, typeof(*last_bb), list);
968eb8a55e0SNamhyung Kim first_bb = list_first_entry(full_blocks, typeof(*first_bb), list);
969eb8a55e0SNamhyung Kim
970eb8a55e0SNamhyung Kim if (list_empty(full_blocks))
971eb8a55e0SNamhyung Kim goto out;
972eb8a55e0SNamhyung Kim
973eb8a55e0SNamhyung Kim /* Last insn in this_blocks should be same as first insn in full_blocks */
974eb8a55e0SNamhyung Kim if (last_bb->end != first_bb->begin) {
975eb8a55e0SNamhyung Kim pr_debug("prepend basic blocks: mismatched disasm line %"PRIx64" -> %"PRIx64"\n",
976eb8a55e0SNamhyung Kim last_bb->end->al.offset, first_bb->begin->al.offset);
977eb8a55e0SNamhyung Kim goto out;
978eb8a55e0SNamhyung Kim }
979eb8a55e0SNamhyung Kim
980eb8a55e0SNamhyung Kim /* Is the basic block have only one disasm_line? */
981eb8a55e0SNamhyung Kim if (last_bb->begin == last_bb->end) {
982eb8a55e0SNamhyung Kim list_del(&last_bb->list);
983eb8a55e0SNamhyung Kim free(last_bb);
984eb8a55e0SNamhyung Kim goto out;
985eb8a55e0SNamhyung Kim }
986eb8a55e0SNamhyung Kim
987eb8a55e0SNamhyung Kim /* Point to the insn before the last when adding this block to full_blocks */
988eb8a55e0SNamhyung Kim last_bb->end = list_prev_entry(last_bb->end, al.node);
989eb8a55e0SNamhyung Kim
990eb8a55e0SNamhyung Kim out:
991eb8a55e0SNamhyung Kim list_splice(this_blocks, full_blocks);
992eb8a55e0SNamhyung Kim }
993eb8a55e0SNamhyung Kim
delete_basic_blocks(struct list_head * basic_blocks)994eb8a55e0SNamhyung Kim static void delete_basic_blocks(struct list_head *basic_blocks)
995eb8a55e0SNamhyung Kim {
996eb8a55e0SNamhyung Kim struct annotated_basic_block *bb, *tmp;
997eb8a55e0SNamhyung Kim
998eb8a55e0SNamhyung Kim list_for_each_entry_safe(bb, tmp, basic_blocks, list) {
999eb8a55e0SNamhyung Kim list_del(&bb->list);
1000eb8a55e0SNamhyung Kim free(bb);
1001eb8a55e0SNamhyung Kim }
1002eb8a55e0SNamhyung Kim }
1003eb8a55e0SNamhyung Kim
1004eb8a55e0SNamhyung Kim /* Make sure all variables have a valid start address */
fixup_var_address(struct die_var_type * var_types,u64 addr)1005eb8a55e0SNamhyung Kim static void fixup_var_address(struct die_var_type *var_types, u64 addr)
1006eb8a55e0SNamhyung Kim {
1007eb8a55e0SNamhyung Kim while (var_types) {
1008eb8a55e0SNamhyung Kim /*
1009eb8a55e0SNamhyung Kim * Some variables have no address range meaning it's always
1010eb8a55e0SNamhyung Kim * available in the whole scope. Let's adjust the start
1011eb8a55e0SNamhyung Kim * address to the start of the scope.
1012eb8a55e0SNamhyung Kim */
1013eb8a55e0SNamhyung Kim if (var_types->addr == 0)
1014eb8a55e0SNamhyung Kim var_types->addr = addr;
1015eb8a55e0SNamhyung Kim
1016eb8a55e0SNamhyung Kim var_types = var_types->next;
1017eb8a55e0SNamhyung Kim }
1018eb8a55e0SNamhyung Kim }
1019eb8a55e0SNamhyung Kim
delete_var_types(struct die_var_type * var_types)1020eb8a55e0SNamhyung Kim static void delete_var_types(struct die_var_type *var_types)
1021eb8a55e0SNamhyung Kim {
1022eb8a55e0SNamhyung Kim while (var_types) {
1023eb8a55e0SNamhyung Kim struct die_var_type *next = var_types->next;
1024eb8a55e0SNamhyung Kim
1025eb8a55e0SNamhyung Kim free(var_types);
1026eb8a55e0SNamhyung Kim var_types = next;
1027eb8a55e0SNamhyung Kim }
1028eb8a55e0SNamhyung Kim }
1029eb8a55e0SNamhyung Kim
1030b3c95109SNamhyung Kim /* should match to is_stack_canary() in util/annotate.c */
setup_stack_canary(struct data_loc_info * dloc)1031b3c95109SNamhyung Kim static void setup_stack_canary(struct data_loc_info *dloc)
1032b3c95109SNamhyung Kim {
1033b3c95109SNamhyung Kim if (arch__is(dloc->arch, "x86")) {
1034b3c95109SNamhyung Kim dloc->op->segment = INSN_SEG_X86_GS;
1035b3c95109SNamhyung Kim dloc->op->imm = true;
1036b3c95109SNamhyung Kim dloc->op->offset = 40;
1037b3c95109SNamhyung Kim }
1038b3c95109SNamhyung Kim }
1039b3c95109SNamhyung Kim
1040bd62de08SNamhyung Kim /*
1041bd62de08SNamhyung Kim * It's at the target address, check if it has a matching type.
104269e2c784SNamhyung Kim * It returns PERF_TMR_BAIL_OUT when it looks up per-cpu variables which
1043bd62de08SNamhyung Kim * are similar to global variables and no additional info is needed.
1044bd62de08SNamhyung Kim */
check_matching_type(struct type_state * state,struct data_loc_info * dloc,Dwarf_Die * cu_die,struct disasm_line * dl,Dwarf_Die * type_die)104569e2c784SNamhyung Kim static enum type_match_result check_matching_type(struct type_state *state,
1046af89e8f2SNamhyung Kim struct data_loc_info *dloc,
104769e2c784SNamhyung Kim Dwarf_Die *cu_die,
1048895891daSNamhyung Kim struct disasm_line *dl,
104969e2c784SNamhyung Kim Dwarf_Die *type_die)
1050eb8a55e0SNamhyung Kim {
1051bdc80aceSNamhyung Kim Dwarf_Word size;
1052895891daSNamhyung Kim u32 insn_offset = dl->al.offset;
1053af89e8f2SNamhyung Kim int reg = dloc->op->reg1;
1054a0d57c60SNamhyung Kim int offset = dloc->op->offset;
1055a0d57c60SNamhyung Kim const char *offset_sign = "";
1056895891daSNamhyung Kim bool retry = true;
1057bdc80aceSNamhyung Kim
1058a0d57c60SNamhyung Kim if (offset < 0) {
1059a0d57c60SNamhyung Kim offset = -offset;
1060a0d57c60SNamhyung Kim offset_sign = "-";
1061a0d57c60SNamhyung Kim }
1062a0d57c60SNamhyung Kim
1063895891daSNamhyung Kim again:
1064a0d57c60SNamhyung Kim pr_debug_dtp("chk [%x] reg%d offset=%s%#x ok=%d kind=%d ",
1065a0d57c60SNamhyung Kim insn_offset, reg, offset_sign, offset,
1066f5b09592SNamhyung Kim state->regs[reg].ok, state->regs[reg].kind);
1067bdc80aceSNamhyung Kim
10684d6d6e0fSNamhyung Kim if (!state->regs[reg].ok)
10694d6d6e0fSNamhyung Kim goto check_non_register;
10704d6d6e0fSNamhyung Kim
10714d6d6e0fSNamhyung Kim if (state->regs[reg].kind == TSR_KIND_TYPE) {
107290d78e7bSNamhyung Kim Dwarf_Die sized_type;
1073a0d57c60SNamhyung Kim struct strbuf sb;
1074a0d57c60SNamhyung Kim
1075a0d57c60SNamhyung Kim strbuf_init(&sb, 32);
1076a0d57c60SNamhyung Kim die_get_typename_from_type(&state->regs[reg].type, &sb);
1077a0d57c60SNamhyung Kim pr_debug_dtp("(%s)", sb.buf);
1078a0d57c60SNamhyung Kim strbuf_release(&sb);
1079bdc80aceSNamhyung Kim
1080bdc80aceSNamhyung Kim /*
1081bdc80aceSNamhyung Kim * Normal registers should hold a pointer (or array) to
1082bdc80aceSNamhyung Kim * dereference a memory location.
1083bdc80aceSNamhyung Kim */
108498d1f1dcSNamhyung Kim if (!is_pointer_type(&state->regs[reg].type)) {
10854449c904SNamhyung Kim if (dloc->op->offset < 0 && reg != state->stack_reg)
10864449c904SNamhyung Kim goto check_kernel;
10874449c904SNamhyung Kim
108869e2c784SNamhyung Kim return PERF_TMR_NO_POINTER;
10894449c904SNamhyung Kim }
10904449c904SNamhyung Kim
1091bdc80aceSNamhyung Kim /* Remove the pointer and get the target type */
109290d78e7bSNamhyung Kim if (__die_get_real_type(&state->regs[reg].type, type_die) == NULL)
109369e2c784SNamhyung Kim return PERF_TMR_NO_POINTER;
1094bdc80aceSNamhyung Kim
1095bdc80aceSNamhyung Kim dloc->type_offset = dloc->op->offset;
1096bdc80aceSNamhyung Kim
109790d78e7bSNamhyung Kim if (dwarf_tag(type_die) == DW_TAG_typedef)
109890d78e7bSNamhyung Kim die_get_real_type(type_die, &sized_type);
109990d78e7bSNamhyung Kim else
110090d78e7bSNamhyung Kim sized_type = *type_die;
110190d78e7bSNamhyung Kim
1102bdc80aceSNamhyung Kim /* Get the size of the actual type */
110390d78e7bSNamhyung Kim if (dwarf_aggregate_size(&sized_type, &size) < 0 ||
1104bdc80aceSNamhyung Kim (unsigned)dloc->type_offset >= size)
110569e2c784SNamhyung Kim return PERF_TMR_BAD_OFFSET;
1106bdc80aceSNamhyung Kim
110769e2c784SNamhyung Kim return PERF_TMR_OK;
1108bdc80aceSNamhyung Kim }
1109bdc80aceSNamhyung Kim
11104d6d6e0fSNamhyung Kim if (state->regs[reg].kind == TSR_KIND_POINTER) {
11114d6d6e0fSNamhyung Kim pr_debug_dtp("percpu ptr");
11124d6d6e0fSNamhyung Kim
11134d6d6e0fSNamhyung Kim /*
11144d6d6e0fSNamhyung Kim * It's actaully pointer but the address was calculated using
11154d6d6e0fSNamhyung Kim * some arithmetic. So it points to the actual type already.
11164d6d6e0fSNamhyung Kim */
11174d6d6e0fSNamhyung Kim *type_die = state->regs[reg].type;
11184d6d6e0fSNamhyung Kim
11194d6d6e0fSNamhyung Kim dloc->type_offset = dloc->op->offset;
11204d6d6e0fSNamhyung Kim
11214d6d6e0fSNamhyung Kim /* Get the size of the actual type */
11224d6d6e0fSNamhyung Kim if (dwarf_aggregate_size(type_die, &size) < 0 ||
11234d6d6e0fSNamhyung Kim (unsigned)dloc->type_offset >= size)
11244d6d6e0fSNamhyung Kim return PERF_TMR_BAIL_OUT;
11254d6d6e0fSNamhyung Kim
11264d6d6e0fSNamhyung Kim return PERF_TMR_OK;
11274d6d6e0fSNamhyung Kim }
11284d6d6e0fSNamhyung Kim
11294d6d6e0fSNamhyung Kim if (state->regs[reg].kind == TSR_KIND_CANARY) {
11304d6d6e0fSNamhyung Kim pr_debug_dtp("stack canary");
11314d6d6e0fSNamhyung Kim
11324d6d6e0fSNamhyung Kim /*
11334d6d6e0fSNamhyung Kim * This is a saved value of the stack canary which will be handled
11344d6d6e0fSNamhyung Kim * in the outer logic when it returns failure here. Pretend it's
11354d6d6e0fSNamhyung Kim * from the stack canary directly.
11364d6d6e0fSNamhyung Kim */
11374d6d6e0fSNamhyung Kim setup_stack_canary(dloc);
11384d6d6e0fSNamhyung Kim
11394d6d6e0fSNamhyung Kim return PERF_TMR_BAIL_OUT;
11404d6d6e0fSNamhyung Kim }
11414d6d6e0fSNamhyung Kim
11424d6d6e0fSNamhyung Kim if (state->regs[reg].kind == TSR_KIND_PERCPU_BASE) {
11434d6d6e0fSNamhyung Kim u64 var_addr = dloc->op->offset;
11444d6d6e0fSNamhyung Kim int var_offset;
11454d6d6e0fSNamhyung Kim
11464d6d6e0fSNamhyung Kim pr_debug_dtp("percpu var");
11474d6d6e0fSNamhyung Kim
11484d6d6e0fSNamhyung Kim if (dloc->op->multi_regs) {
11494d6d6e0fSNamhyung Kim int reg2 = dloc->op->reg2;
11504d6d6e0fSNamhyung Kim
11514d6d6e0fSNamhyung Kim if (dloc->op->reg2 == reg)
11524d6d6e0fSNamhyung Kim reg2 = dloc->op->reg1;
11534d6d6e0fSNamhyung Kim
11544d6d6e0fSNamhyung Kim if (has_reg_type(state, reg2) && state->regs[reg2].ok &&
11554d6d6e0fSNamhyung Kim state->regs[reg2].kind == TSR_KIND_CONST)
11564d6d6e0fSNamhyung Kim var_addr += state->regs[reg2].imm_value;
11574d6d6e0fSNamhyung Kim }
11584d6d6e0fSNamhyung Kim
11594d6d6e0fSNamhyung Kim if (get_global_var_type(cu_die, dloc, dloc->ip, var_addr,
11604d6d6e0fSNamhyung Kim &var_offset, type_die)) {
11614d6d6e0fSNamhyung Kim dloc->type_offset = var_offset;
11624d6d6e0fSNamhyung Kim return PERF_TMR_OK;
11634d6d6e0fSNamhyung Kim }
11644d6d6e0fSNamhyung Kim /* No need to retry per-cpu (global) variables */
11654d6d6e0fSNamhyung Kim return PERF_TMR_BAIL_OUT;
11664d6d6e0fSNamhyung Kim }
11674d6d6e0fSNamhyung Kim
11684d6d6e0fSNamhyung Kim check_non_register:
1169f4dc5a33SNamhyung Kim if (reg == dloc->fbreg || reg == state->stack_reg) {
1170bdc80aceSNamhyung Kim struct type_state_stack *stack;
1171bdc80aceSNamhyung Kim
1172f4dc5a33SNamhyung Kim pr_debug_dtp("%s", reg == dloc->fbreg ? "fbreg" : "stack");
1173bdc80aceSNamhyung Kim
1174bdc80aceSNamhyung Kim stack = find_stack_state(state, dloc->type_offset);
1175895891daSNamhyung Kim if (stack == NULL) {
1176895891daSNamhyung Kim if (retry) {
1177895891daSNamhyung Kim pr_debug_dtp(" : retry\n");
1178895891daSNamhyung Kim retry = false;
1179895891daSNamhyung Kim
1180895891daSNamhyung Kim /* update type info it's the first store to the stack */
1181895891daSNamhyung Kim update_insn_state(state, dloc, cu_die, dl);
1182895891daSNamhyung Kim goto again;
1183895891daSNamhyung Kim }
118469e2c784SNamhyung Kim return PERF_TMR_NO_TYPE;
1185895891daSNamhyung Kim }
1186bdc80aceSNamhyung Kim
1187b3c95109SNamhyung Kim if (stack->kind == TSR_KIND_CANARY) {
1188b3c95109SNamhyung Kim setup_stack_canary(dloc);
118969e2c784SNamhyung Kim return PERF_TMR_BAIL_OUT;
1190b3c95109SNamhyung Kim }
1191b3c95109SNamhyung Kim
1192b7d4aacfSNamhyung Kim if (stack->kind != TSR_KIND_TYPE)
119369e2c784SNamhyung Kim return PERF_TMR_NO_TYPE;
1194b7d4aacfSNamhyung Kim
1195bdc80aceSNamhyung Kim *type_die = stack->type;
1196bdc80aceSNamhyung Kim /* Update the type offset from the start of slot */
1197bdc80aceSNamhyung Kim dloc->type_offset -= stack->offset;
1198bdc80aceSNamhyung Kim
119969e2c784SNamhyung Kim return PERF_TMR_OK;
1200bdc80aceSNamhyung Kim }
1201bdc80aceSNamhyung Kim
1202bdc80aceSNamhyung Kim if (dloc->fb_cfa) {
1203bdc80aceSNamhyung Kim struct type_state_stack *stack;
1204bdc80aceSNamhyung Kim u64 pc = map__rip_2objdump(dloc->ms->map, dloc->ip);
1205bdc80aceSNamhyung Kim int fbreg, fboff;
1206bdc80aceSNamhyung Kim
120769e2c784SNamhyung Kim pr_debug_dtp("cfa");
1208bdc80aceSNamhyung Kim
1209bdc80aceSNamhyung Kim if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fboff) < 0)
1210bdc80aceSNamhyung Kim fbreg = -1;
1211bdc80aceSNamhyung Kim
1212bdc80aceSNamhyung Kim if (reg != fbreg)
121369e2c784SNamhyung Kim return PERF_TMR_NO_TYPE;
1214bdc80aceSNamhyung Kim
1215bdc80aceSNamhyung Kim stack = find_stack_state(state, dloc->type_offset - fboff);
1216895891daSNamhyung Kim if (stack == NULL) {
1217895891daSNamhyung Kim if (retry) {
1218895891daSNamhyung Kim pr_debug_dtp(" : retry\n");
1219895891daSNamhyung Kim retry = false;
1220895891daSNamhyung Kim
1221895891daSNamhyung Kim /* update type info it's the first store to the stack */
1222895891daSNamhyung Kim update_insn_state(state, dloc, cu_die, dl);
1223895891daSNamhyung Kim goto again;
1224895891daSNamhyung Kim }
122569e2c784SNamhyung Kim return PERF_TMR_NO_TYPE;
1226895891daSNamhyung Kim }
1227bdc80aceSNamhyung Kim
1228b3c95109SNamhyung Kim if (stack->kind == TSR_KIND_CANARY) {
1229b3c95109SNamhyung Kim setup_stack_canary(dloc);
123069e2c784SNamhyung Kim return PERF_TMR_BAIL_OUT;
1231b3c95109SNamhyung Kim }
1232b3c95109SNamhyung Kim
1233b7d4aacfSNamhyung Kim if (stack->kind != TSR_KIND_TYPE)
123469e2c784SNamhyung Kim return PERF_TMR_NO_TYPE;
1235b7d4aacfSNamhyung Kim
1236bdc80aceSNamhyung Kim *type_die = stack->type;
1237bdc80aceSNamhyung Kim /* Update the type offset from the start of slot */
1238bdc80aceSNamhyung Kim dloc->type_offset -= fboff + stack->offset;
1239bdc80aceSNamhyung Kim
124069e2c784SNamhyung Kim return PERF_TMR_OK;
1241bdc80aceSNamhyung Kim }
1242bdc80aceSNamhyung Kim
12434449c904SNamhyung Kim check_kernel:
1244ee756ef7SIan Rogers if (dso__kernel(map__dso(dloc->ms->map))) {
124502e17ca9SNamhyung Kim u64 addr;
124602e17ca9SNamhyung Kim
1247f5b09592SNamhyung Kim /* Direct this-cpu access like "%gs:0x34740" */
12484449c904SNamhyung Kim if (dloc->op->segment == INSN_SEG_X86_GS && dloc->op->imm &&
12494449c904SNamhyung Kim arch__is(dloc->arch, "x86")) {
125069e2c784SNamhyung Kim pr_debug_dtp("this-cpu var");
125102e17ca9SNamhyung Kim
125202e17ca9SNamhyung Kim addr = dloc->op->offset;
125302e17ca9SNamhyung Kim
125402e17ca9SNamhyung Kim if (get_global_var_type(cu_die, dloc, dloc->ip, addr,
125502e17ca9SNamhyung Kim &offset, type_die)) {
125602e17ca9SNamhyung Kim dloc->type_offset = offset;
125769e2c784SNamhyung Kim return PERF_TMR_OK;
125802e17ca9SNamhyung Kim }
125969e2c784SNamhyung Kim return PERF_TMR_BAIL_OUT;
1260f5b09592SNamhyung Kim }
1261f5b09592SNamhyung Kim
12624449c904SNamhyung Kim /* Access to global variable like "-0x7dcf0500(,%rdx,8)" */
1263f5b09592SNamhyung Kim if (dloc->op->offset < 0 && reg != state->stack_reg) {
1264f5b09592SNamhyung Kim addr = (s64) dloc->op->offset;
1265f5b09592SNamhyung Kim
12664449c904SNamhyung Kim if (get_global_var_type(cu_die, dloc, dloc->ip, addr,
1267f5b09592SNamhyung Kim &offset, type_die)) {
126869e2c784SNamhyung Kim pr_debug_dtp("global var");
1269f5b09592SNamhyung Kim
1270f5b09592SNamhyung Kim dloc->type_offset = offset;
127169e2c784SNamhyung Kim return PERF_TMR_OK;
1272f5b09592SNamhyung Kim }
127369e2c784SNamhyung Kim return PERF_TMR_BAIL_OUT;
127402e17ca9SNamhyung Kim }
127502e17ca9SNamhyung Kim }
127602e17ca9SNamhyung Kim
127769e2c784SNamhyung Kim return PERF_TMR_UNKNOWN;
1278eb8a55e0SNamhyung Kim }
1279eb8a55e0SNamhyung Kim
1280eb8a55e0SNamhyung Kim /* Iterate instructions in basic blocks and update type table */
find_data_type_insn(struct data_loc_info * dloc,struct list_head * basic_blocks,struct die_var_type * var_types,Dwarf_Die * cu_die,Dwarf_Die * type_die)128169e2c784SNamhyung Kim static enum type_match_result find_data_type_insn(struct data_loc_info *dloc,
1282eb8a55e0SNamhyung Kim struct list_head *basic_blocks,
1283eb8a55e0SNamhyung Kim struct die_var_type *var_types,
128469e2c784SNamhyung Kim Dwarf_Die *cu_die,
128569e2c784SNamhyung Kim Dwarf_Die *type_die)
1286eb8a55e0SNamhyung Kim {
1287eb8a55e0SNamhyung Kim struct type_state state;
1288eb8a55e0SNamhyung Kim struct symbol *sym = dloc->ms->sym;
1289eb8a55e0SNamhyung Kim struct annotation *notes = symbol__annotation(sym);
1290eb8a55e0SNamhyung Kim struct annotated_basic_block *bb;
129169e2c784SNamhyung Kim enum type_match_result ret = PERF_TMR_UNKNOWN;
1292eb8a55e0SNamhyung Kim
1293eb8a55e0SNamhyung Kim init_type_state(&state, dloc->arch);
1294eb8a55e0SNamhyung Kim
1295eb8a55e0SNamhyung Kim list_for_each_entry(bb, basic_blocks, list) {
1296eb8a55e0SNamhyung Kim struct disasm_line *dl = bb->begin;
1297eb8a55e0SNamhyung Kim
1298879ebf3cSNamhyung Kim BUG_ON(bb->begin->al.offset == -1 || bb->end->al.offset == -1);
1299879ebf3cSNamhyung Kim
1300eb8a55e0SNamhyung Kim pr_debug_dtp("bb: [%"PRIx64" - %"PRIx64"]\n",
1301eb8a55e0SNamhyung Kim bb->begin->al.offset, bb->end->al.offset);
1302eb8a55e0SNamhyung Kim
1303eb8a55e0SNamhyung Kim list_for_each_entry_from(dl, ¬es->src->source, al.node) {
1304eb8a55e0SNamhyung Kim u64 this_ip = sym->start + dl->al.offset;
1305eb8a55e0SNamhyung Kim u64 addr = map__rip_2objdump(dloc->ms->map, this_ip);
1306eb8a55e0SNamhyung Kim
1307879ebf3cSNamhyung Kim /* Skip comment or debug info lines */
1308879ebf3cSNamhyung Kim if (dl->al.offset == -1)
1309879ebf3cSNamhyung Kim continue;
1310879ebf3cSNamhyung Kim
1311eb8a55e0SNamhyung Kim /* Update variable type at this address */
1312eb8a55e0SNamhyung Kim update_var_state(&state, dloc, addr, dl->al.offset, var_types);
1313eb8a55e0SNamhyung Kim
1314eb8a55e0SNamhyung Kim if (this_ip == dloc->ip) {
1315af89e8f2SNamhyung Kim ret = check_matching_type(&state, dloc,
1316895891daSNamhyung Kim cu_die, dl, type_die);
131769e2c784SNamhyung Kim pr_debug_dtp(" : %s\n", match_result_str(ret));
1318eb8a55e0SNamhyung Kim goto out;
1319eb8a55e0SNamhyung Kim }
1320eb8a55e0SNamhyung Kim
1321eb8a55e0SNamhyung Kim /* Update type table after processing the instruction */
1322eb8a55e0SNamhyung Kim update_insn_state(&state, dloc, cu_die, dl);
1323eb8a55e0SNamhyung Kim if (dl == bb->end)
1324eb8a55e0SNamhyung Kim break;
1325eb8a55e0SNamhyung Kim }
1326eb8a55e0SNamhyung Kim }
1327eb8a55e0SNamhyung Kim
1328eb8a55e0SNamhyung Kim out:
1329eb8a55e0SNamhyung Kim exit_type_state(&state);
1330bd62de08SNamhyung Kim return ret;
1331eb8a55e0SNamhyung Kim }
1332eb8a55e0SNamhyung Kim
arch_supports_insn_tracking(struct data_loc_info * dloc)133388444952SAthira Rajeev static int arch_supports_insn_tracking(struct data_loc_info *dloc)
133488444952SAthira Rajeev {
133588444952SAthira Rajeev if ((arch__is(dloc->arch, "x86")) || (arch__is(dloc->arch, "powerpc")))
133688444952SAthira Rajeev return 1;
133788444952SAthira Rajeev return 0;
133888444952SAthira Rajeev }
133988444952SAthira Rajeev
1340eb8a55e0SNamhyung Kim /*
1341eb8a55e0SNamhyung Kim * Construct a list of basic blocks for each scope with variables and try to find
1342eb8a55e0SNamhyung Kim * the data type by updating a type state table through instructions.
1343eb8a55e0SNamhyung Kim */
find_data_type_block(struct data_loc_info * dloc,Dwarf_Die * cu_die,Dwarf_Die * scopes,int nr_scopes,Dwarf_Die * type_die)134469e2c784SNamhyung Kim static enum type_match_result find_data_type_block(struct data_loc_info *dloc,
134569e2c784SNamhyung Kim Dwarf_Die *cu_die,
134669e2c784SNamhyung Kim Dwarf_Die *scopes,
134769e2c784SNamhyung Kim int nr_scopes,
134869e2c784SNamhyung Kim Dwarf_Die *type_die)
1349eb8a55e0SNamhyung Kim {
1350eb8a55e0SNamhyung Kim LIST_HEAD(basic_blocks);
1351eb8a55e0SNamhyung Kim struct die_var_type *var_types = NULL;
1352eb8a55e0SNamhyung Kim u64 src_ip, dst_ip, prev_dst_ip;
135369e2c784SNamhyung Kim enum type_match_result ret = PERF_TMR_UNKNOWN;
1354eb8a55e0SNamhyung Kim
1355eb8a55e0SNamhyung Kim /* TODO: other architecture support */
135688444952SAthira Rajeev if (!arch_supports_insn_tracking(dloc))
135769e2c784SNamhyung Kim return PERF_TMR_BAIL_OUT;
1358eb8a55e0SNamhyung Kim
1359eb8a55e0SNamhyung Kim prev_dst_ip = dst_ip = dloc->ip;
1360eb8a55e0SNamhyung Kim for (int i = nr_scopes - 1; i >= 0; i--) {
1361eb8a55e0SNamhyung Kim Dwarf_Addr base, start, end;
1362eb8a55e0SNamhyung Kim LIST_HEAD(this_blocks);
1363eb8a55e0SNamhyung Kim
1364eb8a55e0SNamhyung Kim if (dwarf_ranges(&scopes[i], 0, &base, &start, &end) < 0)
1365eb8a55e0SNamhyung Kim break;
1366eb8a55e0SNamhyung Kim
136702648783SNamhyung Kim pr_debug_dtp("scope: [%d/%d] ", i + 1, nr_scopes);
136802648783SNamhyung Kim pr_debug_scope(&scopes[i]);
136902648783SNamhyung Kim
1370eb8a55e0SNamhyung Kim src_ip = map__objdump_2rip(dloc->ms->map, start);
1371eb8a55e0SNamhyung Kim
1372eb8a55e0SNamhyung Kim again:
1373eb8a55e0SNamhyung Kim /* Get basic blocks for this scope */
1374eb8a55e0SNamhyung Kim if (annotate_get_basic_blocks(dloc->ms->sym, src_ip, dst_ip,
1375eb8a55e0SNamhyung Kim &this_blocks) < 0) {
1376eb8a55e0SNamhyung Kim /* Try previous block if they are not connected */
1377eb8a55e0SNamhyung Kim if (prev_dst_ip != dst_ip) {
1378eb8a55e0SNamhyung Kim dst_ip = prev_dst_ip;
1379eb8a55e0SNamhyung Kim goto again;
1380eb8a55e0SNamhyung Kim }
1381eb8a55e0SNamhyung Kim
1382eb8a55e0SNamhyung Kim pr_debug_dtp("cannot find a basic block from %"PRIx64" to %"PRIx64"\n",
1383eb8a55e0SNamhyung Kim src_ip - dloc->ms->sym->start,
1384eb8a55e0SNamhyung Kim dst_ip - dloc->ms->sym->start);
1385eb8a55e0SNamhyung Kim continue;
1386eb8a55e0SNamhyung Kim }
1387eb8a55e0SNamhyung Kim prepend_basic_blocks(&this_blocks, &basic_blocks);
1388eb8a55e0SNamhyung Kim
1389eb8a55e0SNamhyung Kim /* Get variable info for this scope and add to var_types list */
1390eb8a55e0SNamhyung Kim die_collect_vars(&scopes[i], &var_types);
1391eb8a55e0SNamhyung Kim fixup_var_address(var_types, start);
1392eb8a55e0SNamhyung Kim
1393eb8a55e0SNamhyung Kim /* Find from start of this scope to the target instruction */
139469e2c784SNamhyung Kim ret = find_data_type_insn(dloc, &basic_blocks, var_types,
1395bd62de08SNamhyung Kim cu_die, type_die);
139669e2c784SNamhyung Kim if (ret == PERF_TMR_OK) {
1397eba1f853SNamhyung Kim char buf[64];
1398a0d57c60SNamhyung Kim int offset = dloc->op->offset;
1399a0d57c60SNamhyung Kim const char *offset_sign = "";
1400a0d57c60SNamhyung Kim
1401a0d57c60SNamhyung Kim if (offset < 0) {
1402a0d57c60SNamhyung Kim offset = -offset;
1403a0d57c60SNamhyung Kim offset_sign = "-";
1404a0d57c60SNamhyung Kim }
1405eba1f853SNamhyung Kim
1406eba1f853SNamhyung Kim if (dloc->op->multi_regs)
1407eba1f853SNamhyung Kim snprintf(buf, sizeof(buf), "reg%d, reg%d",
1408eba1f853SNamhyung Kim dloc->op->reg1, dloc->op->reg2);
1409eba1f853SNamhyung Kim else
1410eba1f853SNamhyung Kim snprintf(buf, sizeof(buf), "reg%d", dloc->op->reg1);
1411eba1f853SNamhyung Kim
1412a0d57c60SNamhyung Kim pr_debug_dtp("found by insn track: %s%#x(%s) type-offset=%#x\n",
1413a0d57c60SNamhyung Kim offset_sign, offset, buf, dloc->type_offset);
1414eb8a55e0SNamhyung Kim break;
1415eb8a55e0SNamhyung Kim }
1416eb8a55e0SNamhyung Kim
141769e2c784SNamhyung Kim if (ret == PERF_TMR_BAIL_OUT)
1418bd62de08SNamhyung Kim break;
1419bd62de08SNamhyung Kim
1420eb8a55e0SNamhyung Kim /* Go up to the next scope and find blocks to the start */
1421eb8a55e0SNamhyung Kim prev_dst_ip = dst_ip;
1422eb8a55e0SNamhyung Kim dst_ip = src_ip;
1423eb8a55e0SNamhyung Kim }
1424eb8a55e0SNamhyung Kim
1425eb8a55e0SNamhyung Kim delete_basic_blocks(&basic_blocks);
1426eb8a55e0SNamhyung Kim delete_var_types(var_types);
1427eb8a55e0SNamhyung Kim return ret;
1428eb8a55e0SNamhyung Kim }
1429eb8a55e0SNamhyung Kim
1430b9c87f53SNamhyung Kim /* The result will be saved in @type_die */
find_data_type_die(struct data_loc_info * dloc,Dwarf_Die * type_die)1431a3f4d5b5SNamhyung Kim static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die)
1432b9c87f53SNamhyung Kim {
1433a3f4d5b5SNamhyung Kim struct annotated_op_loc *loc = dloc->op;
1434b9c87f53SNamhyung Kim Dwarf_Die cu_die, var_die;
1435b9c87f53SNamhyung Kim Dwarf_Die *scopes = NULL;
1436a0d57c60SNamhyung Kim int reg, offset = loc->offset;
1437b9c87f53SNamhyung Kim int ret = -1;
1438b9c87f53SNamhyung Kim int i, nr_scopes;
1439bc10db8eSNamhyung Kim int fbreg = -1;
1440bc10db8eSNamhyung Kim int fb_offset = 0;
1441a3f4d5b5SNamhyung Kim bool is_fbreg = false;
1442ba883370SNamhyung Kim bool found = false;
1443a3f4d5b5SNamhyung Kim u64 pc;
144490429524SNamhyung Kim char buf[64];
1445023aceecSNamhyung Kim enum type_match_result result = PERF_TMR_UNKNOWN;
1446a0d57c60SNamhyung Kim const char *offset_sign = "";
144790429524SNamhyung Kim
144890429524SNamhyung Kim if (dloc->op->multi_regs)
14492bc3cf57SNamhyung Kim snprintf(buf, sizeof(buf), "reg%d, reg%d", dloc->op->reg1, dloc->op->reg2);
145090429524SNamhyung Kim else if (dloc->op->reg1 == DWARF_REG_PC)
14512bc3cf57SNamhyung Kim snprintf(buf, sizeof(buf), "PC");
145290429524SNamhyung Kim else
14532bc3cf57SNamhyung Kim snprintf(buf, sizeof(buf), "reg%d", dloc->op->reg1);
145490429524SNamhyung Kim
1455a0d57c60SNamhyung Kim if (offset < 0) {
1456a0d57c60SNamhyung Kim offset = -offset;
1457a0d57c60SNamhyung Kim offset_sign = "-";
1458a0d57c60SNamhyung Kim }
1459a0d57c60SNamhyung Kim
146090429524SNamhyung Kim pr_debug_dtp("-----------------------------------------------------------\n");
1461a0d57c60SNamhyung Kim pr_debug_dtp("find data type for %s%#x(%s) at %s+%#"PRIx64"\n",
1462a0d57c60SNamhyung Kim offset_sign, offset, buf,
1463a0d57c60SNamhyung Kim dloc->ms->sym->name, dloc->ip - dloc->ms->sym->start);
1464a3f4d5b5SNamhyung Kim
1465a3f4d5b5SNamhyung Kim /*
1466a3f4d5b5SNamhyung Kim * IP is a relative instruction address from the start of the map, as
1467a3f4d5b5SNamhyung Kim * it can be randomized/relocated, it needs to translate to PC which is
1468a3f4d5b5SNamhyung Kim * a file address for DWARF processing.
1469a3f4d5b5SNamhyung Kim */
1470a3f4d5b5SNamhyung Kim pc = map__rip_2objdump(dloc->ms->map, dloc->ip);
1471b9c87f53SNamhyung Kim
1472b9c87f53SNamhyung Kim /* Get a compile_unit for this address */
1473a3f4d5b5SNamhyung Kim if (!find_cu_die(dloc->di, pc, &cu_die)) {
147490429524SNamhyung Kim pr_debug_dtp("cannot find CU for address %"PRIx64"\n", pc);
147561a9741eSNamhyung Kim ann_data_stat.no_cuinfo++;
1476b9c87f53SNamhyung Kim return -1;
1477b9c87f53SNamhyung Kim }
1478b9c87f53SNamhyung Kim
1479d3030191SNamhyung Kim reg = loc->reg1;
1480d3030191SNamhyung Kim offset = loc->offset;
1481d3030191SNamhyung Kim
14822bc3cf57SNamhyung Kim pr_debug_dtp("CU for %s (die:%#lx)\n",
14832bc3cf57SNamhyung Kim dwarf_diename(&cu_die), (long)dwarf_dieoffset(&cu_die));
148490429524SNamhyung Kim
14855f7cdde8SNamhyung Kim if (reg == DWARF_REG_PC) {
14861ebb5e17SNamhyung Kim if (get_global_var_type(&cu_die, dloc, dloc->ip, dloc->var_addr,
14871ebb5e17SNamhyung Kim &offset, type_die)) {
1488a3f4d5b5SNamhyung Kim dloc->type_offset = offset;
148990429524SNamhyung Kim
14902bc3cf57SNamhyung Kim pr_debug_dtp("found by addr=%#"PRIx64" type_offset=%#x\n",
149190429524SNamhyung Kim dloc->var_addr, offset);
149265785213SNamhyung Kim pr_debug_type_name(type_die, TSR_KIND_TYPE);
1493023aceecSNamhyung Kim found = true;
149483bfa06dSNamhyung Kim goto out;
149583bfa06dSNamhyung Kim }
14965f7cdde8SNamhyung Kim }
14975f7cdde8SNamhyung Kim
149883bfa06dSNamhyung Kim /* Get a list of nested scopes - i.e. (inlined) functions and blocks. */
149983bfa06dSNamhyung Kim nr_scopes = die_get_scopes(&cu_die, pc, &scopes);
150083bfa06dSNamhyung Kim
1501bc10db8eSNamhyung Kim if (reg != DWARF_REG_PC && dwarf_hasattr(&scopes[0], DW_AT_frame_base)) {
1502bc10db8eSNamhyung Kim Dwarf_Attribute attr;
1503bc10db8eSNamhyung Kim Dwarf_Block block;
1504bc10db8eSNamhyung Kim
1505bc10db8eSNamhyung Kim /* Check if the 'reg' is assigned as frame base register */
1506bc10db8eSNamhyung Kim if (dwarf_attr(&scopes[0], DW_AT_frame_base, &attr) != NULL &&
1507bc10db8eSNamhyung Kim dwarf_formblock(&attr, &block) == 0 && block.length == 1) {
1508bc10db8eSNamhyung Kim switch (*block.data) {
1509bc10db8eSNamhyung Kim case DW_OP_reg0 ... DW_OP_reg31:
1510a3f4d5b5SNamhyung Kim fbreg = dloc->fbreg = *block.data - DW_OP_reg0;
1511bc10db8eSNamhyung Kim break;
1512bc10db8eSNamhyung Kim case DW_OP_call_frame_cfa:
1513a3f4d5b5SNamhyung Kim dloc->fb_cfa = true;
1514a3f4d5b5SNamhyung Kim if (die_get_cfa(dloc->di->dbg, pc, &fbreg,
1515bc10db8eSNamhyung Kim &fb_offset) < 0)
1516bc10db8eSNamhyung Kim fbreg = -1;
1517bc10db8eSNamhyung Kim break;
1518bc10db8eSNamhyung Kim default:
1519bc10db8eSNamhyung Kim break;
1520bc10db8eSNamhyung Kim }
152190429524SNamhyung Kim
152290429524SNamhyung Kim pr_debug_dtp("frame base: cfa=%d fbreg=%d\n",
152390429524SNamhyung Kim dloc->fb_cfa, fbreg);
1524bc10db8eSNamhyung Kim }
1525bc10db8eSNamhyung Kim }
1526bc10db8eSNamhyung Kim
1527d3030191SNamhyung Kim retry:
1528bc10db8eSNamhyung Kim is_fbreg = (reg == fbreg);
1529bc10db8eSNamhyung Kim if (is_fbreg)
1530bc10db8eSNamhyung Kim offset = loc->offset - fb_offset;
1531bc10db8eSNamhyung Kim
1532b9c87f53SNamhyung Kim /* Search from the inner-most scope to the outer */
1533b9c87f53SNamhyung Kim for (i = nr_scopes - 1; i >= 0; i--) {
1534ba883370SNamhyung Kim Dwarf_Die mem_die;
1535ba883370SNamhyung Kim int type_offset = offset;
1536ba883370SNamhyung Kim
153783bfa06dSNamhyung Kim if (reg == DWARF_REG_PC) {
1538a3f4d5b5SNamhyung Kim if (!die_find_variable_by_addr(&scopes[i], dloc->var_addr,
1539ba883370SNamhyung Kim &var_die, &type_offset))
1540b9c87f53SNamhyung Kim continue;
154183bfa06dSNamhyung Kim } else {
154283bfa06dSNamhyung Kim /* Look up variables/parameters in this scope */
154383bfa06dSNamhyung Kim if (!die_find_variable_by_reg(&scopes[i], pc, reg,
1544ba883370SNamhyung Kim &type_offset, is_fbreg, &var_die))
154583bfa06dSNamhyung Kim continue;
154683bfa06dSNamhyung Kim }
1547b9c87f53SNamhyung Kim
1548653185d8SNamhyung Kim pr_debug_dtp("found \"%s\" (die: %#lx) in scope=%d/%d (die: %#lx) ",
1549653185d8SNamhyung Kim dwarf_diename(&var_die), (long)dwarf_dieoffset(&var_die),
1550653185d8SNamhyung Kim i+1, nr_scopes, (long)dwarf_dieoffset(&scopes[i]));
1551653185d8SNamhyung Kim
1552b9c87f53SNamhyung Kim /* Found a variable, see if it's correct */
1553ba883370SNamhyung Kim result = check_variable(dloc, &var_die, &mem_die, reg, type_offset, is_fbreg);
1554976862f8SNamhyung Kim if (result == PERF_TMR_OK) {
15552bc3cf57SNamhyung Kim if (reg == DWARF_REG_PC) {
15562bc3cf57SNamhyung Kim pr_debug_dtp("addr=%#"PRIx64" type_offset=%#x\n",
1557ba883370SNamhyung Kim dloc->var_addr, type_offset);
15582bc3cf57SNamhyung Kim } else if (reg == DWARF_REG_FB || is_fbreg) {
15592bc3cf57SNamhyung Kim pr_debug_dtp("stack_offset=%#x type_offset=%#x\n",
1560ba883370SNamhyung Kim fb_offset, type_offset);
15612bc3cf57SNamhyung Kim } else {
1562ba883370SNamhyung Kim pr_debug_dtp("type_offset=%#x\n", type_offset);
1563b9c87f53SNamhyung Kim }
1564d3030191SNamhyung Kim
1565ba883370SNamhyung Kim if (!found || is_better_type(type_die, &mem_die)) {
1566ba883370SNamhyung Kim *type_die = mem_die;
1567ba883370SNamhyung Kim dloc->type_offset = type_offset;
1568ba883370SNamhyung Kim found = true;
1569ba883370SNamhyung Kim }
1570ba883370SNamhyung Kim } else {
1571ba883370SNamhyung Kim pr_debug_dtp("failed: %s\n", match_result_str(result));
1572ba883370SNamhyung Kim }
1573ba883370SNamhyung Kim
1574ba883370SNamhyung Kim pr_debug_location(&var_die, pc, reg);
1575ba883370SNamhyung Kim pr_debug_type_name(&mem_die, TSR_KIND_TYPE);
1576ba883370SNamhyung Kim }
1577ba883370SNamhyung Kim
1578ba883370SNamhyung Kim if (!found && loc->multi_regs && reg == loc->reg1 && loc->reg1 != loc->reg2) {
1579af89e8f2SNamhyung Kim reg = loc->reg2;
1580af89e8f2SNamhyung Kim goto retry;
1581af89e8f2SNamhyung Kim }
1582af89e8f2SNamhyung Kim
1583ba883370SNamhyung Kim if (!found && reg != DWARF_REG_PC) {
158469e2c784SNamhyung Kim result = find_data_type_block(dloc, &cu_die, scopes,
1585eb8a55e0SNamhyung Kim nr_scopes, type_die);
158669e2c784SNamhyung Kim if (result == PERF_TMR_OK) {
1587eb8a55e0SNamhyung Kim ann_data_stat.insn_track++;
1588ba883370SNamhyung Kim found = true;
1589eb8a55e0SNamhyung Kim }
1590eb8a55e0SNamhyung Kim }
1591eb8a55e0SNamhyung Kim
1592023aceecSNamhyung Kim out:
1593a0d57c60SNamhyung Kim pr_debug_dtp("final result: ");
1594ba883370SNamhyung Kim if (found) {
1595ba883370SNamhyung Kim pr_debug_type_name(type_die, TSR_KIND_TYPE);
1596ba883370SNamhyung Kim ret = 0;
1597ba883370SNamhyung Kim } else {
1598023aceecSNamhyung Kim switch (result) {
1599023aceecSNamhyung Kim case PERF_TMR_NO_TYPE:
1600023aceecSNamhyung Kim case PERF_TMR_NO_POINTER:
1601023aceecSNamhyung Kim pr_debug_dtp("%s\n", match_result_str(result));
1602023aceecSNamhyung Kim ann_data_stat.no_typeinfo++;
1603023aceecSNamhyung Kim break;
1604023aceecSNamhyung Kim case PERF_TMR_NO_SIZE:
1605023aceecSNamhyung Kim pr_debug_dtp("%s\n", match_result_str(result));
1606023aceecSNamhyung Kim ann_data_stat.invalid_size++;
1607023aceecSNamhyung Kim break;
1608023aceecSNamhyung Kim case PERF_TMR_BAD_OFFSET:
1609023aceecSNamhyung Kim pr_debug_dtp("%s\n", match_result_str(result));
1610023aceecSNamhyung Kim ann_data_stat.bad_offset++;
1611023aceecSNamhyung Kim break;
1612023aceecSNamhyung Kim case PERF_TMR_UNKNOWN:
1613023aceecSNamhyung Kim case PERF_TMR_BAIL_OUT:
1614023aceecSNamhyung Kim case PERF_TMR_OK: /* should not reach here */
1615023aceecSNamhyung Kim default:
161690429524SNamhyung Kim pr_debug_dtp("no variable found\n");
161761a9741eSNamhyung Kim ann_data_stat.no_var++;
1618023aceecSNamhyung Kim break;
1619023aceecSNamhyung Kim }
1620023aceecSNamhyung Kim ret = -1;
162190429524SNamhyung Kim }
1622b9c87f53SNamhyung Kim
1623b9c87f53SNamhyung Kim free(scopes);
1624b9c87f53SNamhyung Kim return ret;
1625b9c87f53SNamhyung Kim }
1626b9c87f53SNamhyung Kim
1627b9c87f53SNamhyung Kim /**
1628b9c87f53SNamhyung Kim * find_data_type - Return a data type at the location
1629a3f4d5b5SNamhyung Kim * @dloc: data location
1630b9c87f53SNamhyung Kim *
1631b9c87f53SNamhyung Kim * This functions searches the debug information of the binary to get the data
1632a3f4d5b5SNamhyung Kim * type it accesses. The exact location is expressed by (ip, reg, offset)
1633a3f4d5b5SNamhyung Kim * for pointer variables or (ip, addr) for global variables. Note that global
1634a3f4d5b5SNamhyung Kim * variables might update the @dloc->type_offset after finding the start of the
1635a3f4d5b5SNamhyung Kim * variable. If it cannot find a global variable by address, it tried to find
1636a3f4d5b5SNamhyung Kim * a declaration of the variable using var_name. In that case, @dloc->offset
1637a3f4d5b5SNamhyung Kim * won't be updated.
16385f7cdde8SNamhyung Kim *
1639b9c87f53SNamhyung Kim * It return %NULL if not found.
1640b9c87f53SNamhyung Kim */
find_data_type(struct data_loc_info * dloc)1641a3f4d5b5SNamhyung Kim struct annotated_data_type *find_data_type(struct data_loc_info *dloc)
1642b9c87f53SNamhyung Kim {
1643a3f4d5b5SNamhyung Kim struct dso *dso = map__dso(dloc->ms->map);
1644b9c87f53SNamhyung Kim Dwarf_Die type_die;
1645b9c87f53SNamhyung Kim
1646b9c87f53SNamhyung Kim /*
1647a3f4d5b5SNamhyung Kim * The type offset is the same as instruction offset by default.
1648a3f4d5b5SNamhyung Kim * But when finding a global variable, the offset won't be valid.
1649b9c87f53SNamhyung Kim */
1650a3f4d5b5SNamhyung Kim dloc->type_offset = dloc->op->offset;
1651a3f4d5b5SNamhyung Kim
1652a3f4d5b5SNamhyung Kim dloc->fbreg = -1;
1653a3f4d5b5SNamhyung Kim
1654a3f4d5b5SNamhyung Kim if (find_data_type_die(dloc, &type_die) < 0)
1655037f1b67SNamhyung Kim return NULL;
1656b9c87f53SNamhyung Kim
1657037f1b67SNamhyung Kim return dso__findnew_data_type(dso, &type_die);
1658b9c87f53SNamhyung Kim }
1659fc044c53SNamhyung Kim
alloc_data_type_histograms(struct annotated_data_type * adt,int nr_entries)16609bd7ddd1SNamhyung Kim static int alloc_data_type_histograms(struct annotated_data_type *adt, int nr_entries)
16619bd7ddd1SNamhyung Kim {
16629bd7ddd1SNamhyung Kim int i;
16639bd7ddd1SNamhyung Kim size_t sz = sizeof(struct type_hist);
16649bd7ddd1SNamhyung Kim
16659bd7ddd1SNamhyung Kim sz += sizeof(struct type_hist_entry) * adt->self.size;
16669bd7ddd1SNamhyung Kim
16679bd7ddd1SNamhyung Kim /* Allocate a table of pointers for each event */
16689bd7ddd1SNamhyung Kim adt->histograms = calloc(nr_entries, sizeof(*adt->histograms));
16699bd7ddd1SNamhyung Kim if (adt->histograms == NULL)
16709bd7ddd1SNamhyung Kim return -ENOMEM;
16719bd7ddd1SNamhyung Kim
16729bd7ddd1SNamhyung Kim /*
16739bd7ddd1SNamhyung Kim * Each histogram is allocated for the whole size of the type.
16749bd7ddd1SNamhyung Kim * TODO: Probably we can move the histogram to members.
16759bd7ddd1SNamhyung Kim */
16769bd7ddd1SNamhyung Kim for (i = 0; i < nr_entries; i++) {
16779bd7ddd1SNamhyung Kim adt->histograms[i] = zalloc(sz);
16789bd7ddd1SNamhyung Kim if (adt->histograms[i] == NULL)
16799bd7ddd1SNamhyung Kim goto err;
16809bd7ddd1SNamhyung Kim }
16812af1280bSNamhyung Kim
16822af1280bSNamhyung Kim adt->nr_histograms = nr_entries;
16839bd7ddd1SNamhyung Kim return 0;
16849bd7ddd1SNamhyung Kim
16859bd7ddd1SNamhyung Kim err:
16869bd7ddd1SNamhyung Kim while (--i >= 0)
168769fb6eabSArnaldo Carvalho de Melo zfree(&(adt->histograms[i]));
168869fb6eabSArnaldo Carvalho de Melo zfree(&adt->histograms);
16899bd7ddd1SNamhyung Kim return -ENOMEM;
16909bd7ddd1SNamhyung Kim }
16919bd7ddd1SNamhyung Kim
delete_data_type_histograms(struct annotated_data_type * adt)16929bd7ddd1SNamhyung Kim static void delete_data_type_histograms(struct annotated_data_type *adt)
16939bd7ddd1SNamhyung Kim {
16949bd7ddd1SNamhyung Kim for (int i = 0; i < adt->nr_histograms; i++)
169569fb6eabSArnaldo Carvalho de Melo zfree(&(adt->histograms[i]));
16962af1280bSNamhyung Kim
169769fb6eabSArnaldo Carvalho de Melo zfree(&adt->histograms);
16982af1280bSNamhyung Kim adt->nr_histograms = 0;
16999bd7ddd1SNamhyung Kim }
17009bd7ddd1SNamhyung Kim
annotated_data_type__tree_delete(struct rb_root * root)1701fc044c53SNamhyung Kim void annotated_data_type__tree_delete(struct rb_root *root)
1702fc044c53SNamhyung Kim {
1703fc044c53SNamhyung Kim struct annotated_data_type *pos;
1704fc044c53SNamhyung Kim
1705fc044c53SNamhyung Kim while (!RB_EMPTY_ROOT(root)) {
1706fc044c53SNamhyung Kim struct rb_node *node = rb_first(root);
1707fc044c53SNamhyung Kim
1708fc044c53SNamhyung Kim rb_erase(node, root);
1709fc044c53SNamhyung Kim pos = rb_entry(node, struct annotated_data_type, node);
17104a111cadSNamhyung Kim delete_members(&pos->self);
17119bd7ddd1SNamhyung Kim delete_data_type_histograms(pos);
171269fb6eabSArnaldo Carvalho de Melo zfree(&pos->self.type_name);
1713fc044c53SNamhyung Kim free(pos);
1714fc044c53SNamhyung Kim }
1715fc044c53SNamhyung Kim }
17169bd7ddd1SNamhyung Kim
17179bd7ddd1SNamhyung Kim /**
17189bd7ddd1SNamhyung Kim * annotated_data_type__update_samples - Update histogram
17199bd7ddd1SNamhyung Kim * @adt: Data type to update
17209bd7ddd1SNamhyung Kim * @evsel: Event to update
17219bd7ddd1SNamhyung Kim * @offset: Offset in the type
17229bd7ddd1SNamhyung Kim * @nr_samples: Number of samples at this offset
17239bd7ddd1SNamhyung Kim * @period: Event count at this offset
17249bd7ddd1SNamhyung Kim *
17259bd7ddd1SNamhyung Kim * This function updates type histogram at @ofs for @evsel. Samples are
17269bd7ddd1SNamhyung Kim * aggregated before calling this function so it can be called with more
17279bd7ddd1SNamhyung Kim * than one samples at a certain offset.
17289bd7ddd1SNamhyung Kim */
annotated_data_type__update_samples(struct annotated_data_type * adt,struct evsel * evsel,int offset,int nr_samples,u64 period)17299bd7ddd1SNamhyung Kim int annotated_data_type__update_samples(struct annotated_data_type *adt,
17309bd7ddd1SNamhyung Kim struct evsel *evsel, int offset,
17319bd7ddd1SNamhyung Kim int nr_samples, u64 period)
17329bd7ddd1SNamhyung Kim {
17339bd7ddd1SNamhyung Kim struct type_hist *h;
17349bd7ddd1SNamhyung Kim
17359bd7ddd1SNamhyung Kim if (adt == NULL)
17369bd7ddd1SNamhyung Kim return 0;
17379bd7ddd1SNamhyung Kim
17389bd7ddd1SNamhyung Kim if (adt->histograms == NULL) {
17399bd7ddd1SNamhyung Kim int nr = evsel->evlist->core.nr_entries;
17409bd7ddd1SNamhyung Kim
17419bd7ddd1SNamhyung Kim if (alloc_data_type_histograms(adt, nr) < 0)
17429bd7ddd1SNamhyung Kim return -1;
17439bd7ddd1SNamhyung Kim }
17449bd7ddd1SNamhyung Kim
17459bd7ddd1SNamhyung Kim if (offset < 0 || offset >= adt->self.size)
17469bd7ddd1SNamhyung Kim return -1;
17479bd7ddd1SNamhyung Kim
17489bd7ddd1SNamhyung Kim h = adt->histograms[evsel->core.idx];
17499bd7ddd1SNamhyung Kim
17509bd7ddd1SNamhyung Kim h->nr_samples += nr_samples;
17519bd7ddd1SNamhyung Kim h->addr[offset].nr_samples += nr_samples;
17529bd7ddd1SNamhyung Kim h->period += period;
17539bd7ddd1SNamhyung Kim h->addr[offset].period += period;
17549bd7ddd1SNamhyung Kim return 0;
17559bd7ddd1SNamhyung Kim }
17569b561be1SNamhyung Kim
print_annotated_data_header(struct hist_entry * he,struct evsel * evsel)17579b561be1SNamhyung Kim static void print_annotated_data_header(struct hist_entry *he, struct evsel *evsel)
17589b561be1SNamhyung Kim {
17599b561be1SNamhyung Kim struct dso *dso = map__dso(he->ms.map);
17609b561be1SNamhyung Kim int nr_members = 1;
17619b561be1SNamhyung Kim int nr_samples = he->stat.nr_events;
17629b561be1SNamhyung Kim int width = 7;
17639b561be1SNamhyung Kim const char *val_hdr = "Percent";
17649b561be1SNamhyung Kim
17659b561be1SNamhyung Kim if (evsel__is_group_event(evsel)) {
17669b561be1SNamhyung Kim struct hist_entry *pair;
17679b561be1SNamhyung Kim
17689b561be1SNamhyung Kim list_for_each_entry(pair, &he->pairs.head, pairs.node)
17699b561be1SNamhyung Kim nr_samples += pair->stat.nr_events;
17709b561be1SNamhyung Kim }
17719b561be1SNamhyung Kim
17729b561be1SNamhyung Kim printf("Annotate type: '%s' in %s (%d samples):\n",
1773ee756ef7SIan Rogers he->mem_type->self.type_name, dso__name(dso), nr_samples);
17749b561be1SNamhyung Kim
17759b561be1SNamhyung Kim if (evsel__is_group_event(evsel)) {
17769b561be1SNamhyung Kim struct evsel *pos;
17779b561be1SNamhyung Kim int i = 0;
17789b561be1SNamhyung Kim
1779cb1898f5SNamhyung Kim nr_members = 0;
1780cb1898f5SNamhyung Kim for_each_group_evsel(pos, evsel) {
1781cb1898f5SNamhyung Kim if (symbol_conf.skip_empty &&
1782cb1898f5SNamhyung Kim evsel__hists(pos)->stats.nr_samples == 0)
1783cb1898f5SNamhyung Kim continue;
17849b561be1SNamhyung Kim
1785cb1898f5SNamhyung Kim printf(" event[%d] = %s\n", i++, pos->name);
1786cb1898f5SNamhyung Kim nr_members++;
1787cb1898f5SNamhyung Kim }
17889b561be1SNamhyung Kim }
17899b561be1SNamhyung Kim
17909b561be1SNamhyung Kim if (symbol_conf.show_total_period) {
17919b561be1SNamhyung Kim width = 11;
17929b561be1SNamhyung Kim val_hdr = "Period";
17939b561be1SNamhyung Kim } else if (symbol_conf.show_nr_samples) {
17949b561be1SNamhyung Kim width = 7;
17959b561be1SNamhyung Kim val_hdr = "Samples";
17969b561be1SNamhyung Kim }
17979b561be1SNamhyung Kim
17989b561be1SNamhyung Kim printf("============================================================================\n");
17999b561be1SNamhyung Kim printf("%*s %10s %10s %s\n", (width + 1) * nr_members, val_hdr,
18009b561be1SNamhyung Kim "offset", "size", "field");
18019b561be1SNamhyung Kim }
18029b561be1SNamhyung Kim
print_annotated_data_value(struct type_hist * h,u64 period,int nr_samples)18039b561be1SNamhyung Kim static void print_annotated_data_value(struct type_hist *h, u64 period, int nr_samples)
18049b561be1SNamhyung Kim {
18059b561be1SNamhyung Kim double percent = h->period ? (100.0 * period / h->period) : 0;
18069b561be1SNamhyung Kim const char *color = get_percent_color(percent);
18079b561be1SNamhyung Kim
18089b561be1SNamhyung Kim if (symbol_conf.show_total_period)
18099b561be1SNamhyung Kim color_fprintf(stdout, color, " %11" PRIu64, period);
18109b561be1SNamhyung Kim else if (symbol_conf.show_nr_samples)
18119b561be1SNamhyung Kim color_fprintf(stdout, color, " %7d", nr_samples);
18129b561be1SNamhyung Kim else
18139b561be1SNamhyung Kim color_fprintf(stdout, color, " %7.2f", percent);
18149b561be1SNamhyung Kim }
18159b561be1SNamhyung Kim
print_annotated_data_type(struct annotated_data_type * mem_type,struct annotated_member * member,struct evsel * evsel,int indent)18169b561be1SNamhyung Kim static void print_annotated_data_type(struct annotated_data_type *mem_type,
18179b561be1SNamhyung Kim struct annotated_member *member,
18189b561be1SNamhyung Kim struct evsel *evsel, int indent)
18199b561be1SNamhyung Kim {
18209b561be1SNamhyung Kim struct annotated_member *child;
18219b561be1SNamhyung Kim struct type_hist *h = mem_type->histograms[evsel->core.idx];
1822cb1898f5SNamhyung Kim int i, nr_events = 0, samples = 0;
18239b561be1SNamhyung Kim u64 period = 0;
18249b561be1SNamhyung Kim int width = symbol_conf.show_total_period ? 11 : 7;
18259b561be1SNamhyung Kim struct evsel *pos;
18269b561be1SNamhyung Kim
1827cb1898f5SNamhyung Kim for_each_group_evsel(pos, evsel) {
18289b561be1SNamhyung Kim h = mem_type->histograms[pos->core.idx];
18299b561be1SNamhyung Kim
1830cb1898f5SNamhyung Kim if (symbol_conf.skip_empty &&
1831cb1898f5SNamhyung Kim evsel__hists(pos)->stats.nr_samples == 0)
1832cb1898f5SNamhyung Kim continue;
1833cb1898f5SNamhyung Kim
18349b561be1SNamhyung Kim samples = 0;
18359b561be1SNamhyung Kim period = 0;
18369b561be1SNamhyung Kim for (i = 0; i < member->size; i++) {
18379b561be1SNamhyung Kim samples += h->addr[member->offset + i].nr_samples;
18389b561be1SNamhyung Kim period += h->addr[member->offset + i].period;
18399b561be1SNamhyung Kim }
18409b561be1SNamhyung Kim print_annotated_data_value(h, period, samples);
1841cb1898f5SNamhyung Kim nr_events++;
18429b561be1SNamhyung Kim }
18439b561be1SNamhyung Kim
18447a5c2170SNamhyung Kim printf(" %#10x %#10x %*s%s\t%s",
18459b561be1SNamhyung Kim member->offset, member->size, indent, "", member->type_name,
18469b561be1SNamhyung Kim member->var_name ?: "");
18479b561be1SNamhyung Kim
18489b561be1SNamhyung Kim if (!list_empty(&member->children))
18499b561be1SNamhyung Kim printf(" {\n");
18509b561be1SNamhyung Kim
18519b561be1SNamhyung Kim list_for_each_entry(child, &member->children, node)
18529b561be1SNamhyung Kim print_annotated_data_type(mem_type, child, evsel, indent + 4);
18539b561be1SNamhyung Kim
18549b561be1SNamhyung Kim if (!list_empty(&member->children))
18559b561be1SNamhyung Kim printf("%*s}", (width + 1) * nr_events + 24 + indent, "");
18569b561be1SNamhyung Kim printf(";\n");
18579b561be1SNamhyung Kim }
18589b561be1SNamhyung Kim
hist_entry__annotate_data_tty(struct hist_entry * he,struct evsel * evsel)18599b561be1SNamhyung Kim int hist_entry__annotate_data_tty(struct hist_entry *he, struct evsel *evsel)
18609b561be1SNamhyung Kim {
18619b561be1SNamhyung Kim print_annotated_data_header(he, evsel);
18629b561be1SNamhyung Kim print_annotated_data_type(he->mem_type, &he->mem_type->self, evsel, 0);
18639b561be1SNamhyung Kim printf("\n");
18649b561be1SNamhyung Kim
1865d001c7a7SNamhyung Kim /* move to the next entry */
1866d001c7a7SNamhyung Kim return '>';
18679b561be1SNamhyung Kim }
1868