Exemple #1
0
def break_scope_start(
    context: Context,
    scope: Scope,
    from_line_no: Optional[int] = None,
) -> Optional[BreakpointGroup]:
    """
    Create a breakpoint group for all entry points that are relevant (for
    users) for the given `scope`. Return None if we could find no relevant
    location to break on, otherwise return the breakpoint group.

    :param from_line_no: If given, don't consider line numbers lower than or
        equal to `from_line_no`.
    """
    candidates = scope_start_line_nos(scope, from_line_no)
    return BreakpointGroup(context, candidates) if candidates else None
Exemple #2
0
def break_scope_start(context, scope, from_line_no=None):
    """
    Create a breakpoint group for all entry points that are relevant (for
    users) for the given `scope`. Return None if we could find no relevant
    location to break on, otherwise return the breakpoint group.

    :type context: langkit.gdb.context.Context
    :type scope: Scope

    :param int|None from_line_no: If given, don't consider line numbers lower
        than or equal to `from_line_no`.

    :rtype: BreakpointGroup|None
    """
    candidates = scope_start_line_nos(scope, from_line_no)
    return BreakpointGroup(context, candidates) if candidates else None
Exemple #3
0
def break_scope_start(context, scope, from_line_no=None):
    """
    Create a breakpoint group for all entry points that are relevant (for
    users) for the given `scope`. Return None if we could find no relevant
    location to break on, otherwise return the breakpoint group.

    :type context: langkit.gdb.context.Context
    :type scope: Scope

    :param int|None from_line_no: If given, don't consider line numbers lower
        than or equal to `from_line_no`.

    :rtype: BreakpointGroup|None
    """
    candidates = []

    # Consider the first line for this scope's root expression, if any
    events = scope.iter_events(filter=ExprStart)
    try:
        line_no = next(iter(events)).line_no
    except StopIteration:
        # If there is no root expression, just use the first scope line. It's
        # degraded mode because users are interested in expressions rather than
        # scopes.
        candidates.append(scope.line_range.first_line)
    else:
        candidates.append(line_no)

    # Consider memoization return points for properties
    if isinstance(scope, Property):
        lookup_scope = scope.memoization_lookup
        if lookup_scope:
            candidates.extend(m.line_no for m in lookup_scope.events)

    # Filter candidates if needed with `from_line_no`
    if from_line_no:
        candidates = [l for l in candidates if from_line_no < l]

    return BreakpointGroup(context, candidates) if candidates else None
Exemple #4
0
def go_next(context):
    """
    Continue execution until reaching another expression.
    """

    state = context.decode_state()
    if not state:
        print('Selected frame is not in a property.')
        return

    # If execution reached the part of the code where the property is about to
    # return a cached result, just let it return.
    if state.in_memoization_lookup:
        gdb.execute('finish')
        return

    scope_state, current_expr = state.lookup_current_expr()

    if current_expr is None:
        # There are only two possible causes for no currently evaluating
        # expressions: either the property just started (root expression
        # evaluation is ahead), either it is about to return (root expr.  eval.
        # is behind).
        bp_group = break_scope_start(context,
                                     state.property_scope.scope,
                                     from_line_no=state.line_no)

        if bp_group:
            # The first expression is ahead: resume execution until we reach
            # it.
            gdb.execute('continue')
        else:
            gdb.execute('finish')

    else:
        # Depending on the control flow behavior of the currently running
        # expression, the next step can be either its parent expression or any
        # of its sub-expressions.
        next_slocs_candidates = []

        # First look for the point where the current expression terminates its
        # evaluation.
        next_slocs_candidates.append(current_expr.done_event.line_no)

        # Now look for the starting point for all sub-expressions
        for subexpr in current_expr.start_event.sub_expr_start:
            next_slocs_candidates.append(subexpr.line_no)

        BreakpointGroup(context, next_slocs_candidates)
        gdb.execute('continue')

    new_current_expr = None
    new_expr = None

    new_state = context.decode_state()
    if new_state:
        _, new_current_expr = new_state.lookup_current_expr()
        if current_expr:
            new_expr = new_state.lookup_expr(current_expr.expr_id)

    # If we just finished the evaluation of an expression, display its value
    if new_expr and new_expr.is_done:
        print('{} evaluated to {}'.format(expr_repr(new_expr),
                                          new_expr.read(new_state.frame)))

    # Display the expression of most interest, if any
    if new_current_expr:
        print('')
        print('Now evaluating {}'.format(expr_repr(new_current_expr)))
Exemple #5
0
def go_step_inside(context):
    """
    If execution is about to call a property, step inside it. Traverse
    dispatch properties in order to land directly in the dispatched property.
    """
    def continue_until(line_no, hide_output):
        dest_spec = '{}:{}'.format(context.debug_info.filename, line_no)
        gdb.Breakpoint(dest_spec, internal=True, temporary=True)
        gdb.execute('continue', to_string=hide_output)

    # First, look for a property call in the current execution state
    state = context.decode_state()
    if not state:
        print('Selected frame is not in a property.')
        return
    scope_state, current_expr = state.lookup_current_expr()
    target = scope_state.called_property if scope_state else None

    # If we are not inside a property call already, look for all property
    # calls in the current expression.
    if not target and scope_state:
        # Look for property calls that fall under the following line range...
        expr_range = current_expr.start_event.line_range

        # ... and that *don't* fall under these (i.e. exclude calls for nested
        # expressions).
        filter_ranges = [
            expr.line_range for expr in current_expr.start_event.sub_expr_start
        ]

        def filter(e):
            if not isinstance(e, PropertyCall):
                return False
            line_no = event.line_range.first_line
            if line_no not in expr_range:
                return False
            for fr in filter_ranges:
                if line_no in fr:
                    return False
            return True

        targets = [
            event.property(context)
            for event in scope_state.scope.iter_events() if filter(event)
        ]
        if len(targets) == 1:
            target = targets[0]

    # Still no call target in sight? Just behave like the "next" commmand
    if not target:
        go_next(context)
        return

    # If the target is not a dispatcher, put a temporary breakpoint on the
    # first line in its body and continue to reach it.
    if not target.is_dispatcher:
        bp_group = break_scope_start(context, target)
        if bp_group:
            gdb.execute('continue')
        else:
            go_next(context)
        return

    def frame_signature(frame):
        return str(frame.function())

    # The target is a dispatcher. Look for all property calls it contains,
    # create a breakpoint group for them and continue.
    line_nos = []
    for call in target.iter_events(filter=PropertyCall):
        try:
            prop = call.property(context)
        except KeyError:
            # This happens when the called property is actually a stub
            # (abstract runtime check). No need to put a breakpoint, there.
            pass
        else:
            line_nos.extend(scope_start_line_nos(prop))
    BreakpointGroup(context, line_nos)
    gdb.execute('continue')