xref: /linux-6.15/tools/perf/util/annotate-data.c (revision ce2289ad)
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(&reg->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(&copy_reg->type, &orig_type) ||
9231cfd01ebSNamhyung Kim 				    !is_better_type(&copy_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, &notes->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