Made main memory access via the Memory view work
[Mograsim.git] / plugins / net.mograsim.plugin.core / src / net / mograsim / plugin / launch / MachineDebugTarget.java
1 package net.mograsim.plugin.launch;
2
3 import java.util.Arrays;
4
5 import org.eclipse.core.resources.IMarkerDelta;
6 import org.eclipse.core.runtime.IStatus;
7 import org.eclipse.core.runtime.PlatformObject;
8 import org.eclipse.core.runtime.Status;
9 import org.eclipse.debug.core.DebugEvent;
10 import org.eclipse.debug.core.DebugException;
11 import org.eclipse.debug.core.DebugPlugin;
12 import org.eclipse.debug.core.ILaunch;
13 import org.eclipse.debug.core.ILaunchConfiguration;
14 import org.eclipse.debug.core.model.IBreakpoint;
15 import org.eclipse.debug.core.model.IDebugElement;
16 import org.eclipse.debug.core.model.IDebugTarget;
17 import org.eclipse.debug.core.model.IMemoryBlock;
18 import org.eclipse.debug.core.model.IMemoryBlockExtension;
19 import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
20 import org.eclipse.debug.core.model.IProcess;
21 import org.eclipse.debug.core.model.IStepFilters;
22 import org.eclipse.debug.core.model.IThread;
23
24 import net.mograsim.machine.Machine;
25 import net.mograsim.plugin.MograsimActivator;
26
27 public class MachineDebugTarget extends PlatformObject implements IDebugTarget, IMemoryBlockRetrievalExtension
28 {
29         private final MachineProcess process;
30
31         public MachineDebugTarget(MachineProcess process)
32         {
33                 this.process = process;
34
35                 DebugPlugin.getDefault().addDebugEventListener(es -> Arrays.stream(es).filter(e -> e.getSource() == process).forEach(e ->
36                 {
37                         switch (e.getKind())
38                         {
39                         case DebugEvent.RESUME:
40                                 fireResumeEvent(e.getDetail());
41                                 break;
42                         case DebugEvent.SUSPEND:
43                                 fireSuspendEvent(e.getDetail());
44                                 break;
45                         case DebugEvent.TERMINATE:
46                                 fireTerminateEvent();
47                                 break;
48                         default:
49                                 // ignore
50                         }
51                 }));
52
53                 getLaunch().addDebugTarget(this);
54                 fireCreationEvent();
55         }
56
57         public Machine getMachine()
58         {
59                 return process.getMachine();
60         }
61
62         @Override
63         public String getName() throws DebugException
64         {
65                 return process.getName();
66         }
67
68         @Override
69         public String getModelIdentifier()
70         {
71                 return MograsimActivator.PLUGIN_ID;
72         }
73
74         @Override
75         public IDebugTarget getDebugTarget()
76         {
77                 return this;
78         }
79
80         @Override
81         public ILaunch getLaunch()
82         {
83                 return process.getLaunch();
84         }
85
86         public void setExecutionSpeed(double speed)
87         {
88                 process.setExecutionSpeed(speed);
89         }
90
91         @Override
92         public boolean isSuspended()
93         {
94                 return process.isSuspended();
95         }
96
97         @Override
98         public boolean canSuspend()
99         {
100                 return process.canSuspend();
101         }
102
103         @Override
104         public void suspend() throws DebugException
105         {
106                 process.suspend();
107         }
108
109         @Override
110         public boolean canResume()
111         {
112                 return process.canResume();
113         }
114
115         @Override
116         public void resume() throws DebugException
117         {
118                 process.resume();
119         }
120
121         @Override
122         public boolean isTerminated()
123         {
124                 return process.isTerminated();
125         }
126
127         @Override
128         public boolean canTerminate()
129         {
130                 return process.canTerminate();
131         }
132
133         @Override
134         public void terminate() throws DebugException
135         {
136                 process.terminate();
137         }
138
139         @Override
140         public boolean supportsBreakpoint(IBreakpoint breakpoint)
141         {
142                 return false;
143         }
144
145         @Override
146         public void breakpointAdded(IBreakpoint breakpoint)
147         {
148                 // ignore; we don't support breakpoints
149         }
150
151         @Override
152         public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta)
153         {
154                 // ignore; we don't support breakpoints
155         }
156
157         @Override
158         public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta)
159         {
160                 // ignore; we don't support breakpoints
161         }
162
163         @Override
164         public boolean isDisconnected()
165         {
166                 return false;
167         }
168
169         @Override
170         public boolean canDisconnect()
171         {
172                 return false;
173         }
174
175         @Override
176         public void disconnect() throws DebugException
177         {
178                 throw new DebugException(new Status(IStatus.ERROR, MograsimActivator.PLUGIN_ID, DebugException.NOT_SUPPORTED,
179                                 "Can't disconnect from a MachineDebugTarget", null));
180         }
181
182         @Override
183         public boolean supportsStorageRetrieval()
184         {
185                 return true;
186         }
187
188         @SuppressWarnings("deprecation") // TODO can we throw a DebugException instead?
189         @Override
190         public IMemoryBlock getMemoryBlock(long startAddress, long length) throws DebugException
191         {
192                 return new MainMemoryBlock(this, startAddress, length);
193         }
194
195         @Override
196         public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException
197         {
198                 return new MainMemoryBlockExtension(this, expression, context);
199         }
200
201         @Override
202         public MachineProcess getProcess()
203         {
204                 return process;
205         }
206
207         @Override
208         public boolean hasThreads() throws DebugException
209         {
210                 return false;
211         }
212
213         @Override
214         public IThread[] getThreads() throws DebugException
215         {
216                 return new IThread[0];
217         }
218
219         @SuppressWarnings("unchecked")
220         @Override
221         public <T> T getAdapter(Class<T> adapter)
222         {
223                 if (adapter == IDebugElement.class)
224                         return (T) this;
225
226                 // leave this here; maybe we implement IStepFilters someday
227                 if (adapter == IStepFilters.class)
228                         if (this instanceof IStepFilters)
229                                 return (T) getDebugTarget();
230
231                 if (adapter == IDebugTarget.class)
232                         return (T) getDebugTarget();
233
234                 if (adapter == ILaunch.class)
235                         return (T) getLaunch();
236
237                 if (adapter == IProcess.class)
238                         return (T) getProcess();
239
240                 // CONTEXTLAUNCHING
241                 if (adapter == ILaunchConfiguration.class)
242                         return (T) getLaunch().getLaunchConfiguration();
243
244                 return super.getAdapter(adapter);
245         }
246
247         /**
248          * Fires a creation event for this debug element.
249          */
250         private void fireCreationEvent()
251         {
252                 fireEvent(new DebugEvent(this, DebugEvent.CREATE));
253         }
254
255         /**
256          * Fires a resume for this debug element with the specified detail code.
257          *
258          * @param detail detail code for the resume event, such as <code>DebugEvent.STEP_OVER</code>
259          */
260         private void fireResumeEvent(int detail)
261         {
262                 fireEvent(new DebugEvent(this, DebugEvent.RESUME, detail));
263         }
264
265         /**
266          * Fires a suspend event for this debug element with the specified detail code.
267          *
268          * @param detail detail code for the suspend event, such as <code>DebugEvent.BREAKPOINT</code>
269          */
270         private void fireSuspendEvent(int detail)
271         {
272                 fireEvent(new DebugEvent(this, DebugEvent.SUSPEND, detail));
273         }
274
275         /**
276          * Fires a terminate event for this debug element.
277          */
278         private void fireTerminateEvent()
279         {
280                 fireEvent(new DebugEvent(this, DebugEvent.TERMINATE));
281         }
282
283         /**
284          * Fires a debug event.
285          *
286          * @param event debug event to fire
287          */
288         private static void fireEvent(DebugEvent event)
289         {
290                 DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { event });
291         }
292 }