From cf51cb6b13aae738151452197ea40bc5d4927b61 Mon Sep 17 00:00:00 2001 From: Mikhail Khodjaiants Date: Mon, 28 Nov 2016 12:28:37 -0500 Subject: [PATCH] Bug 367256 - Debugger doesn't handle invalid breakpoints properly Change-Id: I4a86015c61164edf9a7840acb40b7b74a4cf8e61 --- .../dsf/gdb/service/command/GDBControl.java | 11 ++ .../command/MIAsyncErrorProcessor.java | 124 ++++++++++++++++++ .../service/command/events/MIErrorEvent.java | 15 ++- 3 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIAsyncErrorProcessor.java diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java index 6ce4162379d..6e6e6834d35 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/command/GDBControl.java @@ -67,6 +67,7 @@ import org.eclipse.cdt.dsf.mi.service.command.AbstractMIControl; import org.eclipse.cdt.dsf.mi.service.command.CLIEventProcessor; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.IEventProcessor; +import org.eclipse.cdt.dsf.mi.service.command.MIAsyncErrorProcessor; import org.eclipse.cdt.dsf.mi.service.command.MIControlDMContext; import org.eclipse.cdt.dsf.mi.service.command.MIRunControlEventProcessor; import org.eclipse.cdt.dsf.mi.service.command.output.MIConsoleStreamOutput; @@ -193,6 +194,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { private IEventProcessor fMIEventProcessor; private IEventProcessor fCLICommandProcessor; private IEventProcessor fControlEventProcessor; + private IEventProcessor fMIAsyncErrorProcessor; private Process fBackendProcess; private GdbCommandTimeoutManager fCommandTimeoutManager; @@ -571,6 +573,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { fCLICommandProcessor = createCLIEventProcessor(GDBControl.this, getContext()); fMIEventProcessor = createMIRunControlEventProcessor(GDBControl.this, getContext()); fControlEventProcessor = createControlEventProcessor(); + fMIAsyncErrorProcessor = createMIAsyncErrorProcessor(GDBControl.this); requestMonitor.done(); } @@ -580,6 +583,7 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { fControlEventProcessor.dispose(); fCLICommandProcessor.dispose(); fMIEventProcessor.dispose(); + fMIAsyncErrorProcessor.dispose(); if (fBackendProcess instanceof AbstractCLIProcess) { ((AbstractCLIProcess)fBackendProcess).dispose(); } @@ -730,6 +734,13 @@ public class GDBControl extends AbstractMIControl implements IGDBControl { return new ControlEventProcessor(); } + /** + * @since 5.3 + */ + protected IEventProcessor createMIAsyncErrorProcessor(AbstractMIControl connection) { + return new MIAsyncErrorProcessor(connection); + } + /** @since 5.2 */ protected Process createBackendProcess() throws IOException { if (fMIBackend.isFullGdbConsoleSupported()) { diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIAsyncErrorProcessor.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIAsyncErrorProcessor.java new file mode 100644 index 00000000000..3a263bbf22d --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/MIAsyncErrorProcessor.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2016 Mentor Graphics and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Mentor Graphics - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.cdt.dsf.mi.service.command; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; +import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; +import org.eclipse.cdt.dsf.debug.service.command.ICommandResult; +import org.eclipse.cdt.dsf.debug.service.command.ICommandToken; +import org.eclipse.cdt.dsf.mi.service.command.commands.MICommand; +import org.eclipse.cdt.dsf.mi.service.command.events.MIErrorEvent; +import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; +import org.eclipse.cdt.dsf.mi.service.command.output.MIResultRecord; +import org.eclipse.cdt.dsf.service.DsfSession; + +/** + * In some cases GDB reports 'exec-*' commands failure after the '^running' event is fired. + * For instance, if an invalid breakpoint is set no error is reported but the consequent + * 'exec-continue' command fails. + * + * 36-exec-continue --thread 1 + * 36^running + * *running,thread-id="all" + * (gdb) + * &"Warning:\n" + * &"Cannot insert breakpoint 2.\n" + * &"Cannot access memory at address 0x0\n" + * &"\n" + * 36^error,msg="Command aborted." + * (gdb) + * + * This class handles these type of situations by firing MIErrorEvent when such an error appears. + * + * @since 5.3 + */ +public class MIAsyncErrorProcessor implements IEventProcessor { + + final private ICommandControlService fCommandControl; + + private Map fRunCommands = new HashMap<>(); + + public MIAsyncErrorProcessor(ICommandControlService commandControl) { + super(); + fCommandControl = commandControl; + fCommandControl.addCommandListener(this); + fCommandControl.addEventListener(this); + } + + @Override + public void eventReceived(Object output) { + MIResultRecord rr = ((MIOutput)output).getMIResultRecord(); + // Handling the asynchronous error case, i.e. when the "^running" event + // appears before "^error, msg=" for run control commands. + if (rr != null && MIResultRecord.ERROR.equals(rr.getResultClass())) { + handleAsyncError((MIOutput)output); + } + } + + @Override + public void commandQueued(ICommandToken token) { + } + + @Override + public void commandSent(ICommandToken token) { + } + + @Override + public void commandRemoved(ICommandToken token) { + } + + @SuppressWarnings("unchecked") + @Override + public void commandDone(ICommandToken token, ICommandResult result) { + if (token.getCommand() instanceof MICommand && result instanceof MIInfo && ((MIInfo)result).isRunning()) { + IDMContext ctx = ((MICommand)token.getCommand()).getContext(); + if (ctx instanceof IExecutionDMContext) { + MIResultRecord rr = ((MIInfo)result).getMIOutput().getMIResultRecord(); + if (rr != null) { + fRunCommands.put((IExecutionDMContext)ctx, Integer.valueOf(rr.getToken())); + } + } + } + } + + @Override + public void dispose() { + fCommandControl.removeCommandListener(this); + fCommandControl.removeEventListener(this); + fRunCommands.clear(); + } + + protected ICommandControlService getCommandControl() { + return fCommandControl; + } + + protected void handleAsyncError(MIOutput output) { + int token = output.getMIResultRecord().getToken(); + for (Entry entry : fRunCommands.entrySet()) { + if (entry.getValue().intValue() == token && DsfSession.isSessionActive(entry.getKey().getSessionId())) { + fireStoppedEvent(output, entry.getKey()); + } + } + } + + protected void fireStoppedEvent(final MIOutput output, final IExecutionDMContext ctx) { + DsfSession session = DsfSession.getSession(ctx.getSessionId()); + int token = output.getMIResultRecord().getToken(); + session.dispatchEvent(MIErrorEvent.parse(ctx, token, output.getMIResultRecord().getMIResults(), output.getMIOOBRecords()), null); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/events/MIErrorEvent.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/events/MIErrorEvent.java index 3244bf86831..dc26e92371e 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/events/MIErrorEvent.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/events/MIErrorEvent.java @@ -52,11 +52,13 @@ public class MIErrorEvent extends MIStoppedEvent { return log; } + /** + * @since 5.3 + */ public static MIErrorEvent parse( - IContainerDMContext containerDmc, int token, MIResult[] results, MIOOBRecord[] oobs) - { + IExecutionDMContext execDmc, int token, MIResult[] results, MIOOBRecord[] oobs) { String msg = "", log = ""; //$NON-NLS-1$ //$NON-NLS-2$ - + if (results != null) { for (int i = 0; i < results.length; i++) { String var = results[i].getVariable(); @@ -81,7 +83,12 @@ public class MIErrorEvent extends MIStoppedEvent { } log = sb.toString(); } - return new MIErrorEvent(containerDmc, token, results, oobs, msg, log); + return new MIErrorEvent(execDmc, token, results, oobs, msg, log); + } + + public static MIErrorEvent parse( + IContainerDMContext containerDmc, int token, MIResult[] results, MIOOBRecord[] oobs) { + return MIErrorEvent.parse((IExecutionDMContext)containerDmc, token, results, oobs); } @Override