Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: b2ab447b5fe70711b6f2bb499e5b8696a5235ff7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*******************************************************************************
 * Copyright (c) 2016 Mentor Graphics and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 * Mentor Graphics - Initial API and implementation
 * Umair Sair (Mentor Graphics) - Debugging is stuck when "command aborted" occurs on step return (bug 550165)
 *******************************************************************************/

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.DMContexts;
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<IExecutionDMContext, Integer> 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 "<token>^running" event
		// appears before "<token>^error, msg=<error_message>" 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<MIInfo>) token.getCommand()).getContext();
			IExecutionDMContext execDMCtx = DMContexts.getAncestorOfType(ctx, IExecutionDMContext.class);
			if (execDMCtx != null) {
				MIResultRecord rr = ((MIInfo) result).getMIOutput().getMIResultRecord();
				if (rr != null) {
					fRunCommands.put(execDMCtx, 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<IExecutionDMContext, Integer> 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);
	}
}

Back to the top