Ejemplo n.º 1
0
 def finish_populating_widget_popup(self, widget, popup):
     if ida_kernwin.get_widget_type(widget) == \
             ida_kernwin.BWN_DISASM:
         ida_kernwin.attach_action_to_popup(widget,
                                            popup,
                                            act_name,
                                            None)
Ejemplo n.º 2
0
def show_ctree_graph(create_subgraph=False):
    w = ida_kernwin.get_current_widget()
    if ida_kernwin.get_widget_type(w) == ida_kernwin.BWN_PSEUDOCODE:
        vu = ida_hexrays.get_widget_vdui(w)
        if vu:
            vu.get_current_item(ida_hexrays.USE_MOUSE)
            focusitem = vu.item.e if vu.item.is_citem() else None
            sub = None
            if create_subgraph:
                if not focusitem:
                    return
                sub = "subgraph %x" % focusitem.obj_id
            # create graphviewer
            cg = cfunc_graph_t(focusitem,
                               HRDevHelper.config,
                               close_open=True,
                               subtitle=sub)
            # build graph for current function
            gb = graph_builder_t(cg, None if create_subgraph else vu.cfunc)
            gb.apply_to(focusitem if create_subgraph else vu.cfunc.body,
                        vu.cfunc.body)
            # show graph
            cg.Show()
            # set zoom and dock position
            cg.zoom_and_dock(w)
    return
Ejemplo n.º 3
0
    def finish_populating_widget_popup(self, widget, popup_handle):
        if kw.get_widget_type(widget) == kw.BWN_PSEUDOCODE:

            class FilterHandler(kw.action_handler_t):
                def __init__(self, name):
                    self.name = name
                    kw.action_handler_t.__init__(self)

                def activate(self, ctx):
                    obj = FILTERS[self.name]
                    obj.set_activated(not obj.is_activated())
                    vu = hr.get_widget_vdui(ctx.widget)
                    if vu:
                        vu.refresh_view(not obj.is_activated())
                    return 1

                def update(self, ctx):
                    return kw.AST_ENABLE_FOR_WIDGET

            for name, obj in FILTERS.items():
                action_desc = kw.action_desc_t(
                    '%s%s' % (ACTION_NAME, name), name, FilterHandler(name),
                    None, None, 34 if obj.is_activated() else -1)
                kw.attach_dynamic_action_to_popup(widget, popup_handle,
                                                  action_desc, POPUP_ENTRY)
Ejemplo n.º 4
0
    def get_lines_rendering_info_ev(self, out, widget, rin):
        wt = ida_kernwin.get_widget_type(widget)
        if wt == ida_kernwin.BWN_PSEUDOCODE:
            vu = ida_hexrays.get_widget_vdui(widget)
            if vu:
                cf = vu.cfunc
                if cf.entry_ea not in self.funcs:
                    return

                vusync = self.funcs[cf.entry_ea]
                ea = self.ea
                if ea in vusync:
                    slist = vusync.get_items(ea)
                    for section_lines in rin.sections_lines:
                        for line in section_lines:
                            lnnum = ida_kernwin.place_t.as_simpleline_place_t(line.at).n
                            for sync_info in slist:
                                ix, iy, ilen = sync_info
                                if lnnum == iy:
                                    e = ida_kernwin.line_rendering_output_entry_t(line)
                                    e.bg_color = COLOR
                                    e.cpx = ix
                                    e.nchars = ilen
                                    e.flags |= ida_kernwin.LROEF_CPS_RANGE
                                    out.entries.push_back(e)
        return
Ejemplo n.º 5
0
 def finish_populating_widget_popup(self, widget, popup_handle):
     if ida_kernwin.get_widget_type(widget) == idaapi.BWN_DISASM:
         for item in self.MENU_ITEMS:
             if item.popup:
                 idaapi.attach_action_to_popup(widget, popup_handle,
                                               item.action,
                                               self.plugin_name + "/")
Ejemplo n.º 6
0
    def finish_populating_widget_popup(self, widget, popup_handle):
        if ida_kernwin.get_widget_type(widget) == ida_kernwin.BWN_PSEUDOCODE:

            class menu_handler_t(ida_kernwin.action_handler_t):
                def __init__(self, name):
                    ida_kernwin.action_handler_t.__init__(self)
                    self.name = name

                def activate(self, ctx):
                    if self.name == HRDevHelper.get_action_name(
                            HRDevHelper.act_show_ctree):
                        show_ctree_graph()
                    elif self.name == HRDevHelper.get_action_name(
                            HRDevHelper.act_show_sub_tree):
                        show_ctree_graph(create_subgraph=True)
                    elif self.name == HRDevHelper.get_action_name(
                            HRDevHelper.act_show_context):
                        context_viewer_t.open()
                    else:
                        ida_kernwin.warning("Not implemented")
                    return 1

                def update(self, ctx):
                    return ida_kernwin.AST_ENABLE_FOR_WIDGET

            for actname, data in self.actions.items():
                desc, hotkey = data
                action_desc = ida_kernwin.action_desc_t(
                    actname, desc, menu_handler_t(actname), hotkey, None, -1)
                ida_kernwin.attach_dynamic_action_to_popup(
                    widget, popup_handle, action_desc, "%s/" % PLUGIN_NAME)
Ejemplo n.º 7
0
    def _render_lines(self, lines_out, widget, lines_in):
        """
        (Event) IDA is about to render code viewer lines.
        """
        widget_type = ida_kernwin.get_widget_type(widget)

        if widget_type == ida_kernwin.BWN_DISASM:
            self._highlight_disassesmbly(lines_out, widget, lines_in)

        return
Ejemplo n.º 8
0
Archivo: actions.py Proyecto: ylkcy/src
 def finish_populating_widget_popup(self, widget, popup):
     # We'll add our action to all "IDA View-*"s.
     # If we wanted to add it only to "IDA View-A", we could
     # also discriminate on the widget's title:
     #
     #  if ida_kernwin.get_widget_title(widget) == "IDA View-A":
     #      ...
     #
     if ida_kernwin.get_widget_type(widget) == ida_kernwin.BWN_DISASM:
         ida_kernwin.attach_action_to_popup(widget, popup, act_name, None)
Ejemplo n.º 9
0
 def screen_ea_changed_ev(self, ea, prev_ea):
     # react to screen ea changes issued by PSEUDOCODE and DISASM views
     if (ida_kernwin.get_widget_type(ida_kernwin.get_current_widget()) in
     [ida_kernwin.BWN_PSEUDOCODE, ida_kernwin.BWN_DISASM]):
         self.ea = ea
         # why does refresh_idaview_anyway() work but request_refresh() doesn't?
         #ida_kernwin.clear_refresh_request(ida_kernwin.IWID_PSEUDOCODE)
         #ida_kernwin.request_refresh(ida_kernwin.IWID_PSEUDOCODE, True)
         ida_kernwin.refresh_idaview_anyway()
     return
Ejemplo n.º 10
0
 def render_lines(self, lines_out, widget, lines_in):
     """
     (Event) IDA is about to render code viewer lines.
     """
     widget_type = ida_kernwin.get_widget_type(widget)
     if widget_type == ida_kernwin.BWN_PSEUDOCODE and self._sync_status:
         self._highlight_hexrays(lines_out, widget, lines_in)
     elif widget == self._code_widget:
         self._highlight_microcode(lines_out, widget, lines_in)
     return
Ejemplo n.º 11
0
def make_name():
    """rename current item"""
    """TODO:replace with custom implementation that allows
    parameters such as name and flags ("create name anyway") to be set
    """

    cv = ida_kernwin.get_current_viewer()
    if cv:
        hx = ida_kernwin.get_widget_type(cv) == ida_kernwin.BWN_PSEUDOCODE
        ida_kernwin.process_ui_action("hx:Rename" if hx else "MakeName")
    return
Ejemplo n.º 12
0
 def view_dblclick(self, viewer, point):
     widget_type = ida_kernwin.get_widget_type(viewer)
     if not (widget_type == 48 or widget_type == 28):
         return
     # Decompiler or Structures window
     place, x, y = ida_kernwin.get_custom_viewer_place(viewer, False)
     line = utils.get_curline_striped_from_viewer(viewer)
     func_cand_name = cpp_utils.find_valid_cppname_in_line(line, x)
     if func_cand_name is not None:
         func_cand_ea = ida_name.get_name_ea(BADADDR, func_cand_name)
         if func_cand_ea is not None and utils.is_func(func_cand_ea):
             idc.jumpto(func_cand_ea)
Ejemplo n.º 13
0
def dump_ctree_to_lambda(create_subgraph=False):
    w = ida_kernwin.get_current_widget()
    if ida_kernwin.get_widget_type(w) == ida_kernwin.BWN_PSEUDOCODE:
        vu = ida_hexrays.get_widget_vdui(w)
        if vu:
            vu.get_current_item(ida_hexrays.USE_MOUSE)
            focusitem = vu.cfunc.body
            if create_subgraph:
                focusitem = vu.item.e if vu.item.is_citem() else None
            if focusitem:
                gd = graph_dumper_t()
                gd.apply_to(focusitem, vu.cfunc.body)
                lines = "(%s)" % " and\n".join(gd.lines)
                print("%s\n%x:\n%s" %
                      ("-" * 80, ida_kernwin.get_screen_ea(), lines))
    def finish_populating_widget_popup(self, form, popup):
        tft = ida_kernwin.get_widget_type(form)
        if tft != idaapi.BWN_DISASM:
            return

        pos = idc.get_screen_ea()
        register_dynamic_action(form, popup, 'Decode All IOCTLs in Function', DecodeAllHandler())
        register_dynamic_action(form, popup, 'Decode IOCTLs using Angr', DecodeAngrHandler())
		# If the second argument to the current selected instruction is an immediately
        # then give the option to decode it.
        if idc.get_operand_type(pos, 1) == 5:
            register_dynamic_action(form, popup, 'Decode IOCTL', DecodeHandler())
            if pos in ioctl_tracker.ioctl_locs:
                register_dynamic_action(form, popup, 'Invalid IOCTL', InvalidHandler())
        if len(ioctl_tracker.ioctl_locs) > 0:
            register_dynamic_action(form, popup, 'Show All IOCTLs', ShowAllHandler())
Ejemplo n.º 15
0
def rename_func():
    """rename function, suggests current identifier as function name"""

    name = _get_identifier()
    if name:
        str = ida_kernwin.ask_str(name, -1, "Rename function")
        if str:
            f = ida_funcs.get_func(ida_kernwin.get_screen_ea())
            if f:
                if ida_name.set_name(f.start_ea, str, ida_name.SN_NOCHECK):
                    cv = ida_kernwin.get_current_viewer()
                    if ida_kernwin.get_widget_type(
                            cv) == ida_kernwin.BWN_PSEUDOCODE:
                        vd = ida_hexrays.get_widget_vdui(cv)
                        if vd:
                            vd.refresh_view(True)
    return
Ejemplo n.º 16
0
    def get_custom_viewer_hint(self, view, place):
        try:
            widget = ida_kernwin.get_current_widget()
            if ida_kernwin.get_widget_type(widget) != ida_kernwin.BWN_DISASM:
                return None

            curline = ida_kernwin.get_custom_viewer_curline(view, True)

            # sometimes get_custom_viewer_place() returns [x, y] and sometimes [place_t, x, y].
            # we want the place_t.
            viewer_place = ida_kernwin.get_custom_viewer_place(view, True)
            if len(viewer_place) != 3:
                return None

            _, x, y = viewer_place
            ea = place.toea()

            # "color" is a bit of misnomer: its the type of the symbol currently hinted
            color = get_color_at_char(curline, x)
            if color != ida_lines.COLOR_ADDR:
                return None

            # grab the FAR references to code (not necessarilty a branch/call/jump by itself)
            far_code_references = [
                xref.to for xref in idautils.XrefsFrom(ea, ida_xref.XREF_FAR)
                if ida_bytes.is_code(ida_bytes.get_flags(xref.to))
            ]
            if len(far_code_references) != 1:
                return None

            fva = far_code_references[0]

            # ensure its actually a function
            if not idaapi.get_func(fva):
                return None

            # this magic constant is the number of "important lines" to display by default.
            # the remaining lines get shown if you scroll down while the hint is displayed, revealing more lines.
            return render_function_hint(fva), DEFAULT_IMPORTANT_LINES_NUM
        except Exception as e:
            logger.warning(
                'unexpected exception: %s. Get in touch with @williballenthin.',
                e,
                exc_info=True)
            return None
Ejemplo n.º 17
0
    def run(self, arg):
        w = ida_kernwin.get_current_widget()
        if ida_kernwin.get_widget_type(w) == ida_kernwin.BWN_PSEUDOCODE:
            vu = ida_hexrays.get_widget_vdui(w)
            vu_title = ida_kernwin.get_widget_title(w)
            if vu:
                vu.get_current_item(ida_hexrays.USE_KEYBOARD)
                highlight = vu.item.e if vu.item.is_citem() else None
                # create graphviewer
                cg = cfunc_graph_t(highlight, True)
                # build graph for current function
                gb = graph_builder_t(cg)
                gb.apply_to(vu.cfunc.body, None)
                # show graph
                cg.Show()

                # set zoom and dock position
                cg.zoom_and_dock(vu_title, ZOOM, DOCK_POSITION)
Ejemplo n.º 18
0
 def run(self, arg):
     global tainted_pcs
     # this is called when select the plugin from the Edit>Plugins menu
     curwidget = ida_kernwin.get_current_widget()
     if (ida_kernwin.BWN_PSEUDOCODE == ida_kernwin.get_widget_type(
             curwidget)):
         reuse = HIT2_ReuseDialog.GET_NEW_PROCESS
         clear_old = False
         if (len(tainted_pcs) > 0):
             reuse = HIT2_ReuseDialog.askToReuse()
             if (HIT2_ReuseDialog.GET_NEW_PROCESS == reuse):
                 tainted_pcs.clear()
                 # need to clear old colors in case changing process on the
                 # same decompiled function that colored before
                 clear_old = True
         if (HIT2_ReuseDialog.CANCEL_REQUEST != reuse):
             self.color_pseudocode(curwidget, clear_old)
     else:
         ida_kernwin.msg("Current window is not a pseudocode window\n")
Ejemplo n.º 19
0
    def run(self, arg):
        w = ida_kernwin.get_current_widget()
        if ida_kernwin.get_widget_type(w) == ida_kernwin.BWN_PSEUDOCODE:
            vu = ida_hexrays.get_widget_vdui(w)
            vu_title = ida_kernwin.get_widget_title(w)
            if vu:
                vu.get_current_item(ida_hexrays.USE_KEYBOARD)
                focusitem = vu.item.e if vu.item.is_citem() else None
                # create graphviewer
                cg = cfunc_graph_t(focusitem, self.config, close_open=True)
                # build graph for current function
                gb = graph_builder_t(cg)
                gb.apply_to(vu.cfunc.body, None)
                # show graph
                cg.Show()

                # set zoom and dock position
                cg.zoom_and_dock(vu_title, self.config["options"]["zoom"],
                                 self.config["options"]["dockpos"])
Ejemplo n.º 20
0
    def get_custom_viewer_hint(self, viewer, place):
        widget_type = ida_kernwin.get_widget_type(viewer)
        if widget_type != ida_kernwin.BWN_DISASM:
            return

        flags = ida_bytes.get_flags(place.toea()) if place else 0
        if not ida_bytes.is_code(flags):
            return

        item = AMIE.extract_item(viewer)
        if not item:
            return
        tag, val = item

        hint = self.arch.hint(place.toea(), tag, val)
        if not hint:
            return

        return AMIE.format_hint(*hint)
Ejemplo n.º 21
0
 def view_dblclick(self, viewer, point):
     widget_type = ida_kernwin.get_widget_type(viewer)
     if not (widget_type == 48 or widget_type == 28):
         return
     # Decompiler or Structures window
     func_cand_name = None
     place, x, y = ida_kernwin.get_custom_viewer_place(viewer, False)
     if place.name() == "structplace_t":  # Structure window:
         structplace = ida_kernwin.place_t_as_structplace_t(place)
         if structplace is not None:
             s = ida_struct.get_struc(ida_struct.get_struc_by_idx(structplace.idx))
             if s:
                 member = ida_struct.get_member(s, structplace.offset)
                 if member:
                     func_cand_name = ida_struct.get_member_name(member.id)
     if func_cand_name is None:
         line = utils.get_curline_striped_from_viewer(viewer)
         func_cand_name = cpp_utils.find_valid_cppname_in_line(line, x)
     if func_cand_name is not None:
         func_cand_ea = ida_name.get_name_ea(BADADDR, func_cand_name)
         if func_cand_ea is not None and utils.is_func_start(func_cand_ea):
             idc.jumpto(func_cand_ea)
 def finish_populating_widget_popup(self, w, popup):
     if ida_kernwin.get_widget_type(w) == ida_kernwin.BWN_FUNCS:
         ida_kernwin.attach_action_to_popup(w, popup, ACTION_NAME, None)
Ejemplo n.º 23
0
 def finish_populating_widget_popup(self, w, popup):
     if ida_kernwin.get_widget_type(w) == ida_kernwin.BWN_FUNCS:
         ida_kernwin.attach_action_to_popup(w, popup, ACTION_NAME, None)
Ejemplo n.º 24
0
 def get_lines_rendering_info(self, out, widget, info):
     if kw.get_widget_type(widget) == kw.BWN_PSEUDOCODE:
         for name, obj in FILTERS.items():
             if obj.is_activated():
                 obj.get_lines_rendering_info_ev(out, widget, info)
     return
Ejemplo n.º 25
0
def get_widget_type(form):
    if idaapi.IDA_SDK_VERSION <= 699:
        retval = idaapi.get_tform_type(form)
    else:
        retval = ida_kernwin.get_widget_type(form)
    return retval
Ejemplo n.º 26
0
Archivo: vds8.py Proyecto: AmesianX/src
 def populating_widget_popup(self, widget, popup):
     if ida_kernwin.get_widget_type(widget) == ida_kernwin.BWN_PSEUDOCODE:
         ida_kernwin.attach_action_to_popup(widget, popup, ACTION_NAME)
Ejemplo n.º 27
0
    def _popup_hook(self, widget, popup):
        """
        (Event) IDA is about to show a popup for the given TWidget.
        """

        # TODO: return if plugin/trace is not active
        pass

        # fetch the (IDA) window type (eg, disas, graph, hex ...)
        view_type = ida_kernwin.get_widget_type(widget)

        # only attach these context items to popups in disas views
        if view_type == ida_kernwin.BWN_DISASMS:

            # prep for some shady hacks
            p_qmenu = ctypes.cast(int(popup),
                                  ctypes.POINTER(ctypes.c_void_p))[0]
            qmenu = sip.wrapinstance(int(p_qmenu), QtWidgets.QMenu)

            #
            # inject and organize the Tenet plugin actions
            #

            ida_kernwin.attach_action_to_popup(
                widget,
                popup,
                self.ACTION_NEXT_EXECUTION,  # The action ID (see above)
                "Rename",  # Relative path of where to add the action
                ida_kernwin.SETMENU_APP  # We want to append the action after ^
            )

            #
            # this is part of our bodge to inject a plugin action submenu
            # at a specific location in the QMenu, cuz I don't think it's
            # actually possible with the native IDA API's (for groups...)
            #

            for action in qmenu.actions():
                if action.text() == "Go to next execution":

                    # inject a group for the exta 'go to' actions
                    goto_submenu = QtWidgets.QMenu("Go to...")
                    qmenu.insertMenu(action, goto_submenu)

                    # hold a Qt ref of the submenu so it doesn't GC
                    self.__goto_submenu = goto_submenu
                    break

            ida_kernwin.attach_action_to_popup(
                widget,
                popup,
                self.ACTION_FIRST_EXECUTION,  # The action ID (see above)
                "Go to.../",  # Relative path of where to add the action
                ida_kernwin.SETMENU_APP  # We want to append the action after ^
            )

            ida_kernwin.attach_action_to_popup(
                widget,
                popup,
                self.ACTION_FINAL_EXECUTION,  # The action ID (see above)
                "Go to.../",  # Relative path of where to add the action
                ida_kernwin.SETMENU_APP  # We want to append the action after ^
            )

            ida_kernwin.attach_action_to_popup(
                widget,
                popup,
                self.ACTION_PREV_EXECUTION,  # The action ID (see above)
                "Rename",  # Relative path of where to add the action
                ida_kernwin.SETMENU_APP  # We want to append the action after ^
            )

            #
            # inject a seperator to help insulate our plugin action group
            #

            for action in qmenu.actions():
                if action.text() == "Go to previous execution":
                    qmenu.insertSeparator(action)
                    break
Ejemplo n.º 28
0
 def populating_widget_popup(self, widget, popup):
     if ida_kernwin.get_widget_type(widget) == ida_kernwin.BWN_PSEUDOCODE:
         ida_kernwin.attach_action_to_popup(widget, popup, ACTION_NAME)
Ejemplo n.º 29
0
 def finish_populating_widget_popup(self, form, popup):
     if ida_kernwin.get_widget_type(form) == ida_kernwin.BWN_CPUREGS:
         ida_kernwin.attach_action_to_popup(form, popup, ACTION_NAME)
Ejemplo n.º 30
0
    def finish_populating_widget_popup_ev(self, widget, popup_handle):
        if ida_kernwin.get_widget_type(widget) == ida_kernwin.BWN_PSEUDOCODE:

            class EAHandler(ida_kernwin.action_handler_t):
                def __init__(self, ea):
                    self.ea = ea
                    ida_kernwin.action_handler_t.__init__(self)

                def activate(self, ctx):
                    ida_kernwin.jumpto(self.ea)
                    return 1

                def update(self, ctx):
                    return ida_kernwin.AST_ENABLE_FOR_WIDGET

            class callees_t:
                def __init__(self,
                             start_ea,
                             max_recursion=MAX_DEPTH,
                             max_func=MAX_FUNC):
                    self.ea = start_ea
                    name = ida_name.get_short_name(self.ea)
                    if not len(name):
                        name = "unkn_%x" % self.ea
                    self.base_path = "childs [%s]" % name
                    self.mr = max_recursion
                    self.mf = max_func
                    self.paths = {}
                    self._recurse(self.ea, self.base_path, 0)

                # TODO: check processing of recursive functions
                def _recurse(self, ea, path, depth):
                    if depth >= self.mr:
                        self.paths[path] = [("[...]", BADADDR)]
                        return

                    # for all callees of ea...
                    i = 0
                    for cea in Callees(ea):
                        if i + 1 >= self.mf:
                            self.paths[path].append(("...", BADADDR))
                            break
                        loc_name = ida_name.get_short_name(cea)
                        if not len(loc_name):
                            loc_name = "unkn_%x" % cea
                        elem = (loc_name, cea)
                        # if path doesn't exist yet
                        if path not in self.paths:
                            self.paths[path] = [elem]
                        # if caller doesn't exist yet
                        if elem not in self.paths[path]:
                            self.paths[path].append(elem)
                            i += 1

                        newpath = "%s/%s" % (path, loc_name)
                        self._recurse(cea, newpath, depth + 1)
                    return

            class callers_t:
                def __init__(self,
                             start_ea,
                             max_recursion=MAX_DEPTH,
                             max_func=MAX_FUNC):
                    self.ea = start_ea
                    name = ida_name.get_short_name(self.ea)
                    if not len(name):
                        name = "unkn_%x" % self.ea
                    self.base_path = "parents [%s]" % name
                    self.mr = max_recursion
                    self.mf = max_func
                    self.paths = {}
                    self._recurse(self.ea, self.base_path, 0)

                # TODO: check processing of recursive functions
                def _recurse(self, ea, path, depth):
                    if depth + 1 >= self.mr:
                        self.paths[path] = [("[...]", BADADDR)]
                        return

                    # for all callers of ea...
                    i = 0
                    for ref in idautils.CodeRefsTo(ea, False):
                        if i + 1 >= self.mf:
                            self.paths[path].append(("...", BADADDR))
                            break
                        cea = ref
                        func = ida_funcs.get_func(cea)
                        if func:
                            cea = func.start_ea
                        loc_name = ida_name.get_short_name(cea)
                        if not len(loc_name):
                            loc_name = "unkn_%x" % cea
                        elem = (loc_name, cea)
                        # if path doesn't exist yet
                        if path not in self.paths:
                            self.paths[path] = [elem]
                        # if caller doesn't exist yet
                        if elem not in self.paths[path]:
                            self.paths[path].append(elem)
                            i += 1

                        newpath = "%s/%s" % (path, loc_name)
                        self._recurse(cea, newpath, depth + 1)
                    return

            def build_menu(item_ea):
                callers = callers_t(item_ea)
                for path, info in callers.paths.items():
                    for loc_name, ea in info:
                        desc = ida_kernwin.action_desc_t(
                            "abyss:caller_%s_%s" % (path, loc_name),
                            "%s" % (loc_name), EAHandler(ea), None, None,
                            41 if ea != BADADDR else -1)
                        ida_kernwin.attach_dynamic_action_to_popup(
                            widget, popup_handle, desc,
                            "%s (%d)/" % (path, len(info)),
                            ida_kernwin.SETMENU_APP)

                callees = callees_t(item_ea)
                for path, info in callees.paths.items():
                    for loc_name, ea in info:
                        desc = ida_kernwin.action_desc_t(
                            "abyss:callee_%s_%s" % (path, loc_name),
                            "%s" % (loc_name), EAHandler(ea), None, None,
                            41 if ea != BADADDR else -1)
                        ida_kernwin.attach_dynamic_action_to_popup(
                            widget, popup_handle, desc,
                            "%s (%d)/" % (path, len(info)),
                            ida_kernwin.SETMENU_APP)

            ea = ida_kernwin.get_screen_ea()
            vu = ida_hexrays.get_widget_vdui(widget)
            if vu and vu.get_current_item(ida_hexrays.USE_KEYBOARD):
                if vu.item.it.is_expr(
                ) and vu.item.it.op is ida_hexrays.cot_obj:
                    _ea = vu.item.e.cexpr.obj_ea
                    if _ea != BADADDR:
                        ea = _ea
            pfn = ida_funcs.get_func(ea)
            if pfn and pfn.start_ea == ea:
                build_menu(ea)