Package uk.co.cwspencer.ideagdb.debug.breakpoints

Source Code of uk.co.cwspencer.ideagdb.debug.breakpoints.GdbBreakpointHandler

package uk.co.cwspencer.ideagdb.debug.breakpoints;

import com.intellij.icons.AllIcons;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.util.containers.BidirectionalMap;
import com.intellij.xdebugger.XSourcePosition;
import com.intellij.xdebugger.breakpoints.XBreakpointHandler;
import com.intellij.xdebugger.breakpoints.XLineBreakpoint;
import org.jetbrains.annotations.NotNull;
import uk.co.cwspencer.gdb.Gdb;
import uk.co.cwspencer.gdb.messages.GdbBreakpoint;
import uk.co.cwspencer.gdb.messages.GdbErrorEvent;
import uk.co.cwspencer.gdb.messages.GdbEvent;
import uk.co.cwspencer.ideagdb.debug.GdbDebugProcess;

import java.util.List;

public class GdbBreakpointHandler extends
        XBreakpointHandler<XLineBreakpoint<GdbBreakpointProperties>> {
    private static final Logger m_log =
            Logger.getInstance("#uk.co.cwspencer.ideagdb.debug.breakpoints.GdbBreakpointHandler");

    private Gdb m_gdb;
    private GdbDebugProcess m_debugProcess;

    // The breakpoints that have been set and their GDB breakpoint numbers
    private final BidirectionalMap<Integer, XLineBreakpoint<GdbBreakpointProperties>>
            m_breakpoints = new BidirectionalMap<Integer, XLineBreakpoint<GdbBreakpointProperties>>();

    public GdbBreakpointHandler(Gdb gdb, GdbDebugProcess debugProcess) {
        super(GdbBreakpointType.class);
        m_gdb = gdb;
        m_debugProcess = debugProcess;
    }

    /**
     * Registers the given breakpoint with GDB.
     *
     * @param breakpoint The breakpoint.
     */
    @Override
    public void registerBreakpoint(
        @NotNull final XLineBreakpoint<GdbBreakpointProperties> breakpoint) {
        // TODO: I think we can use tracepoints here if the suspend policy isn't to stop the process

        // Check if the breakpoint already exists
        Integer number = findBreakpointNumber(breakpoint);
        if (number != null) {
            // Re-enable the breakpoint
            m_gdb.sendCommand("-break-enable " + number);
        } else {
            // Set the breakpoint
            XSourcePosition sourcePosition = breakpoint.getSourcePosition();
            if (sourcePosition == null) {
                return;
            }

            String command = "-break-insert -f " + sourcePosition.getFile().getPath() + ":" + (sourcePosition.getLine() + 1);
            m_gdb.sendCommand(command, new Gdb.GdbEventCallback() {
                @Override
                public void onGdbCommandCompleted(GdbEvent event) {
                    onGdbBreakpointReady(event, breakpoint);
                }
            });
        }
    }

    /**
     * Unregisters the given breakpoint with GDB.
     *
     * @param breakpoint The breakpoint.
     * @param temporary  Whether we are deleting the breakpoint or temporarily disabling it.
     */
    @Override
    public void unregisterBreakpoint(@NotNull XLineBreakpoint<GdbBreakpointProperties> breakpoint,
                                     boolean temporary) {
        Integer number = findBreakpointNumber(breakpoint);
        if (number == null) {
            m_log.warn("Cannot remove breakpoint; could not find it in breakpoint table");
            return;
        }

        if (!temporary) {
            // Delete the breakpoint
            m_gdb.sendCommand("-break-delete " + number);
            synchronized (m_breakpoints) {
                m_breakpoints.remove(number);
            }
        } else {
            // Disable the breakpoint
            m_gdb.sendCommand("-break-disable " + number);
        }
    }

    /**
     * Finds a breakpoint by its GDB number.
     *
     * @param number The GDB breakpoint number.
     * @return The breakpoint, or null if it could not be found.
     */
    public XLineBreakpoint<GdbBreakpointProperties> findBreakpoint(int number) {
        synchronized (m_breakpoints) {
            return m_breakpoints.get(number);
        }
    }

    /**
     * Finds a breakpoint's GDB number.
     *
     * @param breakpoint The breakpoint to search for.
     * @return The breakpoint number, or null if it could not be found.
     */
    public Integer findBreakpointNumber(XLineBreakpoint<GdbBreakpointProperties> breakpoint) {
        List<Integer> numbers;
        synchronized (m_breakpoints) {
            numbers = m_breakpoints.getKeysByValue(breakpoint);
        }

        if (numbers == null || numbers.isEmpty()) {
            return null;
        } else if (numbers.size() > 1) {
            m_log.warn("Found multiple breakpoint numbers for breakpoint; only returning the " +
                    "first");
        }
        return numbers.get(0);
    }

    /**
     * Callback function for when GDB has responded to our breakpoint request.
     *
     * @param event      The event.
     * @param breakpoint The breakpoint we tried to set.
     */
    private void onGdbBreakpointReady(GdbEvent event,
                                      XLineBreakpoint<GdbBreakpointProperties> breakpoint) {
        if (event instanceof GdbErrorEvent) {
            m_debugProcess.getSession().updateBreakpointPresentation(breakpoint,
                    AllIcons.Debugger.Db_invalid_breakpoint, ((GdbErrorEvent) event).message);
            return;
        }
        if (!(event instanceof GdbBreakpoint)) {
            m_debugProcess.getSession().updateBreakpointPresentation(breakpoint,
                    AllIcons.Debugger.Db_invalid_breakpoint, "Unexpected data received from GDB");
            m_log.warn("Unexpected event " + event + " received from -break-insert request");
            return;
        }

        // Save the breakpoint
        GdbBreakpoint gdbBreakpoint = (GdbBreakpoint) event;
        if (gdbBreakpoint.number == null) {
            m_debugProcess.getSession().updateBreakpointPresentation(breakpoint,
                    AllIcons.Debugger.Db_invalid_breakpoint, "No breakpoint number received from GDB");
            m_log.warn("No breakpoint number received from GDB after -break-insert request");
            return;
        }

        synchronized (m_breakpoints) {
            m_breakpoints.put(gdbBreakpoint.number, breakpoint);
        }

        // Mark the breakpoint as set
        // TODO: Don't do this yet if the breakpoint is pending
        m_debugProcess.getSession().updateBreakpointPresentation(breakpoint,
                AllIcons.Debugger.Db_verified_breakpoint, null);
    }
}
TOP

Related Classes of uk.co.cwspencer.ideagdb.debug.breakpoints.GdbBreakpointHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.