free(str);
 }
 
+/* Type information in a register, valid when ok is true */
+struct type_state_reg {
+       Dwarf_Die type;
+       bool ok;
+};
+
+/* Type information in a stack location, dynamically allocated */
+struct type_state_stack {
+       struct list_head list;
+       Dwarf_Die type;
+       int offset;
+       int size;
+       bool compound;
+};
+
+/* FIXME: This should be arch-dependent */
+#define TYPE_STATE_MAX_REGS  16
+
+/*
+ * State table to maintain type info in each register and stack location.
+ * It'll be updated when new variable is allocated or type info is moved
+ * to a new location (register or stack).  As it'd be used with the
+ * shortest path of basic blocks, it only maintains a single table.
+ */
+struct type_state {
+       struct type_state_reg regs[TYPE_STATE_MAX_REGS];
+       struct list_head stack_vars;
+};
+
+static bool has_reg_type(struct type_state *state, int reg)
+{
+       return (unsigned)reg < ARRAY_SIZE(state->regs);
+}
+
+/* These declarations will be remove once they are changed to static */
+void init_type_state(struct type_state *state, struct arch *arch __maybe_unused);
+void exit_type_state(struct type_state *state);
+void update_var_state(struct type_state *state, struct data_loc_info *dloc,
+                     u64 addr, u64 insn_offset, struct die_var_type *var_types);
+
+void init_type_state(struct type_state *state, struct arch *arch __maybe_unused)
+{
+       memset(state, 0, sizeof(*state));
+       INIT_LIST_HEAD(&state->stack_vars);
+}
+
+void exit_type_state(struct type_state *state)
+{
+       struct type_state_stack *stack, *tmp;
+
+       list_for_each_entry_safe(stack, tmp, &state->stack_vars, list) {
+               list_del(&stack->list);
+               free(stack);
+       }
+}
+
 /*
  * Compare type name and size to maintain them in a tree.
  * I'm not sure if DWARF would have information of a single type in many
        return 0;
 }
 
+static struct type_state_stack *find_stack_state(struct type_state *state,
+                                                int offset)
+{
+       struct type_state_stack *stack;
+
+       list_for_each_entry(stack, &state->stack_vars, list) {
+               if (offset == stack->offset)
+                       return stack;
+
+               if (stack->compound && stack->offset < offset &&
+                   offset < stack->offset + stack->size)
+                       return stack;
+       }
+       return NULL;
+}
+
+static void set_stack_state(struct type_state_stack *stack, int offset,
+                           Dwarf_Die *type_die)
+{
+       int tag;
+       Dwarf_Word size;
+
+       if (dwarf_aggregate_size(type_die, &size) < 0)
+               size = 0;
+
+       tag = dwarf_tag(type_die);
+
+       stack->type = *type_die;
+       stack->size = size;
+       stack->offset = offset;
+
+       switch (tag) {
+       case DW_TAG_structure_type:
+       case DW_TAG_union_type:
+               stack->compound = true;
+               break;
+       default:
+               stack->compound = false;
+               break;
+       }
+}
+
+static struct type_state_stack *findnew_stack_state(struct type_state *state,
+                                                   int offset, Dwarf_Die *type_die)
+{
+       struct type_state_stack *stack = find_stack_state(state, offset);
+
+       if (stack) {
+               set_stack_state(stack, offset, type_die);
+               return stack;
+       }
+
+       stack = malloc(sizeof(*stack));
+       if (stack) {
+               set_stack_state(stack, offset, type_die);
+               list_add(&stack->list, &state->stack_vars);
+       }
+       return stack;
+}
+
+/**
+ * update_var_state - Update type state using given variables
+ * @state: type state table
+ * @dloc: data location info
+ * @addr: instruction address to match with variable
+ * @insn_offset: instruction offset (for debug)
+ * @var_types: list of variables with type info
+ *
+ * This function fills the @state table using @var_types info.  Each variable
+ * is used only at the given location and updates an entry in the table.
+ */
+void update_var_state(struct type_state *state, struct data_loc_info *dloc,
+                     u64 addr, u64 insn_offset, struct die_var_type *var_types)
+{
+       Dwarf_Die mem_die;
+       struct die_var_type *var;
+       int fbreg = dloc->fbreg;
+       int fb_offset = 0;
+
+       if (dloc->fb_cfa) {
+               if (die_get_cfa(dloc->di->dbg, addr, &fbreg, &fb_offset) < 0)
+                       fbreg = -1;
+       }
+
+       for (var = var_types; var != NULL; var = var->next) {
+               if (var->addr != addr)
+                       continue;
+               /* Get the type DIE using the offset */
+               if (!dwarf_offdie(dloc->di->dbg, var->die_off, &mem_die))
+                       continue;
+
+               if (var->reg == DWARF_REG_FB) {
+                       findnew_stack_state(state, var->offset, &mem_die);
+
+                       pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=",
+                                    insn_offset, -var->offset);
+                       pr_debug_type_name(&mem_die);
+               } else if (var->reg == fbreg) {
+                       findnew_stack_state(state, var->offset - fb_offset, &mem_die);
+
+                       pr_debug_dtp("var [%"PRIx64"] -%#x(stack) type=",
+                                    insn_offset, -var->offset + fb_offset);
+                       pr_debug_type_name(&mem_die);
+               } else if (has_reg_type(state, var->reg) && var->offset == 0) {
+                       struct type_state_reg *reg;
+
+                       reg = &state->regs[var->reg];
+                       reg->type = mem_die;
+                       reg->ok = true;
+
+                       pr_debug_dtp("var [%"PRIx64"] reg%d type=",
+                                    insn_offset, var->reg);
+                       pr_debug_type_name(&mem_die);
+               }
+       }
+}
+
 /* The result will be saved in @type_die */
 static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die)
 {