|
Added
Link Here
|
| 1 |
package org.eclipse.cdt.dsf.gdb.service; |
| 2 |
|
| 3 |
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; |
| 4 |
import org.eclipse.cdt.dsf.concurrent.RequestMonitor; |
| 5 |
import org.eclipse.cdt.dsf.datamodel.DMContexts; |
| 6 |
import org.eclipse.cdt.dsf.datamodel.IDMContext; |
| 7 |
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl; |
| 8 |
import org.eclipse.cdt.dsf.debug.service.command.CommandCache; |
| 9 |
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext; |
| 10 |
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; |
| 11 |
import org.eclipse.cdt.dsf.gdb.service.command.GDBControlDMContext; |
| 12 |
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl; |
| 13 |
import org.eclipse.cdt.dsf.mi.service.IMICommandControl; |
| 14 |
import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; |
| 15 |
import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext; |
| 16 |
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; |
| 17 |
import org.eclipse.cdt.dsf.mi.service.command.output.MIAddInferiorInfo; |
| 18 |
import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; |
| 19 |
import org.eclipse.cdt.dsf.service.DsfSession; |
| 20 |
import org.eclipse.core.runtime.IStatus; |
| 21 |
import org.eclipse.core.runtime.Status; |
| 22 |
|
| 23 |
public class GDBProcesses_7_2 extends GDBProcesses_7_1{ |
| 24 |
|
| 25 |
private CommandFactory fCommandFactory; |
| 26 |
// This cache is used when we send command to get the cores. |
| 27 |
// The value of the cores can change at any time, but we provide |
| 28 |
// an updated value whenever there is a suspended event. |
| 29 |
private CommandCache fCommandForCoresCache; |
| 30 |
private IGDBControl fCommandControl; |
| 31 |
|
| 32 |
// A cache for commands about the threadGroups |
| 33 |
private CommandCache fContainerCommandCache; |
| 34 |
|
| 35 |
|
| 36 |
public GDBProcesses_7_2(DsfSession session) { |
| 37 |
super(session); |
| 38 |
} |
| 39 |
|
| 40 |
@Override |
| 41 |
public void initialize(final RequestMonitor requestMonitor) { |
| 42 |
super.initialize(new RequestMonitor(getExecutor(), requestMonitor) { |
| 43 |
@Override |
| 44 |
protected void handleSuccess() { |
| 45 |
doInitialize(requestMonitor); |
| 46 |
} |
| 47 |
}); |
| 48 |
} |
| 49 |
|
| 50 |
/** |
| 51 |
* This method initializes this service after our superclass's initialize() |
| 52 |
* method succeeds. |
| 53 |
* |
| 54 |
* @param requestMonitor |
| 55 |
* The call-back object to notify when this service's |
| 56 |
* initialization is done. |
| 57 |
*/ |
| 58 |
private void doInitialize(RequestMonitor requestMonitor) { |
| 59 |
fCommandControl = getServicesTracker().getService(IGDBControl.class); |
| 60 |
|
| 61 |
BufferedCommandControl bufferedCommandControl = new BufferedCommandControl(fCommandControl, getExecutor(), 2); |
| 62 |
|
| 63 |
// This caches stores the result of a command when received; also, this cache |
| 64 |
// is manipulated when receiving events. Currently, events are received after |
| 65 |
// three scheduling of the executor, while command results after only one. This |
| 66 |
// can cause problems because command results might be processed before an event |
| 67 |
// that actually arrived before the command result. |
| 68 |
// To solve this, we use a bufferedCommandControl that will delay the command |
| 69 |
// result by two scheduling of the executor. |
| 70 |
// See bug 280461 |
| 71 |
fCommandForCoresCache = new CommandCache(getSession(), |
| 72 |
new BufferedCommandControl(fCommandControl, getExecutor(), 2)); |
| 73 |
fCommandForCoresCache.setContextAvailable(fCommandControl.getContext(), true); |
| 74 |
|
| 75 |
fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); |
| 76 |
|
| 77 |
fContainerCommandCache = new CommandCache(getSession(), bufferedCommandControl); |
| 78 |
fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true); |
| 79 |
|
| 80 |
getSession().addServiceEventListener(this, null); |
| 81 |
|
| 82 |
requestMonitor.done(); |
| 83 |
} |
| 84 |
|
| 85 |
@Override |
| 86 |
public void shutdown(RequestMonitor requestMonitor) { |
| 87 |
getSession().removeServiceEventListener(this); |
| 88 |
|
| 89 |
super.shutdown(requestMonitor); |
| 90 |
} |
| 91 |
|
| 92 |
/* * inferior x |
| 93 |
* (gdb) |
| 94 |
*/ |
| 95 |
|
| 96 |
public void switchInferior(IDMContext dmc, Object selection , final DataRequestMonitor<IProcessDMContext> rm ) { |
| 97 |
char inferiorId = (char) -1; |
| 98 |
if (dmc instanceof GDBControlDMContext) { //regular expressions ile yap |
| 99 |
int start = (selection.toString()).indexOf("["); |
| 100 |
int len = "[".length(); |
| 101 |
int count = 1; |
| 102 |
while (start != -1) { |
| 103 |
start = (selection.toString()).indexOf("[", start+len); |
| 104 |
count++; |
| 105 |
if ( count == 3){ |
| 106 |
inferiorId = (selection.toString()).charAt(start+2); // sadece tek rakamları parse eder 11 , 101 ???? |
| 107 |
} |
| 108 |
} |
| 109 |
|
| 110 |
if ( inferiorId != -1 && isInteger(String.valueOf(inferiorId)) ){ |
| 111 |
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class); |
| 112 |
fCommandControl.queueCommand(fCommandFactory.createCLISwitchInferior(controlDmc ,String.valueOf(inferiorId)), |
| 113 |
new DataRequestMonitor<MIInfo>(getExecutor(), rm) { |
| 114 |
@Override |
| 115 |
protected void handleSuccess() { |
| 116 |
// BUraya sonucu dogrulugu icin info eklenmelidir. |
| 117 |
rm.done(); |
| 118 |
} |
| 119 |
}); |
| 120 |
} |
| 121 |
} else { |
| 122 |
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ |
| 123 |
rm.done(); |
| 124 |
} |
| 125 |
} |
| 126 |
|
| 127 |
public boolean isInteger( String input ) |
| 128 |
{ |
| 129 |
try |
| 130 |
{ |
| 131 |
Integer.parseInt( input ); |
| 132 |
return true; |
| 133 |
} |
| 134 |
catch( Exception e) |
| 135 |
{ |
| 136 |
return false; |
| 137 |
} |
| 138 |
} |
| 139 |
|
| 140 |
@Override |
| 141 |
public void attachDebuggerToProcess(final IProcessDMContext procCtx, final String file , DataRequestMonitor<IDMContext> rm) { |
| 142 |
final IProcessDMContext procDmc = procCtx; |
| 143 |
final DataRequestMonitor<IDMContext> requestmonitor = rm; |
| 144 |
final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(procDmc, ICommandControlDMContext.class); |
| 145 |
fCommandControl.queueCommand(fCommandFactory.createMIAddInferior(controlDmc), |
| 146 |
new DataRequestMonitor<MIAddInferiorInfo>(getExecutor(), requestmonitor) { |
| 147 |
@Override |
| 148 |
protected void handleSuccess() { |
| 149 |
if ( getData().getGroupId() != null ){ |
| 150 |
fCommandControl.queueCommand(fCommandFactory.createCLISwitchInferior(controlDmc ,getData().getGroupId().substring(1, 2)), |
| 151 |
new DataRequestMonitor<MIInfo>(getExecutor(), requestmonitor) { |
| 152 |
@Override |
| 153 |
protected void handleSuccess() { |
| 154 |
if (procCtx instanceof IMIProcessDMContext) { |
| 155 |
DataRequestMonitor<Boolean> rm_bool = new DataRequestMonitor<Boolean>(getExecutor(), requestmonitor); |
| 156 |
isDebuggerAttachSupported(null, rm_bool); |
| 157 |
if (!rm_bool.getData()) { |
| 158 |
requestmonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Attach not supported.", null)); //$NON-NLS-1$ |
| 159 |
requestmonitor.done(); |
| 160 |
return; |
| 161 |
} |
| 162 |
|
| 163 |
final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, ICommandControlDMContext.class); |
| 164 |
fCommandControl.queueCommand( |
| 165 |
fCommandFactory.createMITargetAttach(controlDmc, ((IMIProcessDMContext)procCtx).getProcId()), |
| 166 |
new DataRequestMonitor<MIInfo>(getExecutor(), requestmonitor) { |
| 167 |
@Override |
| 168 |
protected void handleSuccess() { |
| 169 |
fCommandControl.queueCommand( |
| 170 |
fCommandFactory.createMIFileExecAndSymbols(controlDmc, file) , |
| 171 |
|
| 172 |
new DataRequestMonitor<MIInfo>(getExecutor(), requestmonitor)); |
| 173 |
|
| 174 |
IMIContainerDMContext containerDmc = createContainerContext(procCtx, |
| 175 |
((IMIProcessDMContext)procCtx).getProcId()); |
| 176 |
requestmonitor.setData(containerDmc); |
| 177 |
requestmonitor.done(); |
| 178 |
} |
| 179 |
}); |
| 180 |
|
| 181 |
} else { |
| 182 |
requestmonitor.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$ |
| 183 |
requestmonitor.done(); |
| 184 |
} |
| 185 |
} |
| 186 |
}); |
| 187 |
|
| 188 |
} |
| 189 |
|
| 190 |
} |
| 191 |
}); |
| 192 |
rm.done(); |
| 193 |
|
| 194 |
} |
| 195 |
|
| 196 |
/* |
| 197 |
public void eventReceived(Object output) { |
| 198 |
for (MIOOBRecord oobr : ((MIOutput)output).getMIOOBRecords()) { |
| 199 |
if (oobr instanceof MINotifyAsyncOutput) { |
| 200 |
MINotifyAsyncOutput exec = (MINotifyAsyncOutput) oobr; |
| 201 |
String miEvent = exec.getAsyncClass(); |
| 202 |
if ("thread-created".equals(miEvent) || "thread-exited".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ |
| 203 |
String threadId = null; |
| 204 |
String groupId = null; |
| 205 |
|
| 206 |
MIResult[] results = exec.getMIResults(); |
| 207 |
for (int i = 0; i < results.length; i++) { |
| 208 |
String var = results[i].getVariable(); |
| 209 |
MIValue val = results[i].getMIValue(); |
| 210 |
if (var.equals("group-id")) { //$NON-NLS-1$ |
| 211 |
if (val instanceof MIConst) { |
| 212 |
groupId = ((MIConst) val).getString(); |
| 213 |
} |
| 214 |
} else if (var.equals("id")) { //$NON-NLS-1$ |
| 215 |
if (val instanceof MIConst) { |
| 216 |
threadId = ((MIConst) val).getString(); |
| 217 |
} |
| 218 |
} |
| 219 |
} |
| 220 |
|
| 221 |
if ("thread-created".equals(miEvent)) { //$NON-NLS-1$ |
| 222 |
// Update the thread to groupId map with the new groupId |
| 223 |
fThreadToGroupMap.put(threadId, groupId); |
| 224 |
} else { |
| 225 |
fThreadToGroupMap.remove(threadId); |
| 226 |
} |
| 227 |
} else if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent) || //$NON-NLS-1$ //$NON-NLS-2$ |
| 228 |
"thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ |
| 229 |
|
| 230 |
String groupId = null; |
| 231 |
String infNo = null; |
| 232 |
|
| 233 |
MIResult[] results = exec.getMIResults(); |
| 234 |
for (int i = 0; i < results.length; i++) { |
| 235 |
String var = results[i].getVariable(); |
| 236 |
MIValue val = results[i].getMIValue(); |
| 237 |
if (var.equals("pid")) { //$NON-NLS-1$ |
| 238 |
if (val instanceof MIConst) { |
| 239 |
groupId = ((MIConst) val).getString().trim(); |
| 240 |
} |
| 241 |
} |
| 242 |
if (var.equals("id")) { //$NON-NLS-1$ |
| 243 |
if (val instanceof MIConst) { |
| 244 |
infNo = ((MIConst) val).getString().trim(); |
| 245 |
} |
| 246 |
} |
| 247 |
} |
| 248 |
|
| 249 |
if (groupId != null) { |
| 250 |
if ("thread-group-created".equals(miEvent) || "thread-group-started".equals(miEvent)) { //$NON-NLS-1$ //$NON-NLS-2$ |
| 251 |
fDebuggedProcessesAndNames.put(groupId, ""); //$NON-NLS-1$ |
| 252 |
|
| 253 |
// GDB is debugging a new process. Let's fetch its |
| 254 |
// name and remember it. In order to get the name, |
| 255 |
// we have to request all running processes, not |
| 256 |
// just the ones being debugged. We got a lot more |
| 257 |
// information when we request all processes. |
| 258 |
final String finalGroupId = groupId; |
| 259 |
final String finalInfNo = infNo; |
| 260 |
fListThreadGroupsAvailableCache.execute( |
| 261 |
fCommandFactory.createMIListThreadGroups(fCommandControl.getContext(), true), |
| 262 |
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), null) { |
| 263 |
@Override |
| 264 |
protected void handleCompleted() { |
| 265 |
// We cannot actually cache this command since the process |
| 266 |
// list may change. But this cache allows to avoid overlapping |
| 267 |
// sending of this command. |
| 268 |
fListThreadGroupsAvailableCache.reset(); |
| 269 |
|
| 270 |
if (isSuccess()) { |
| 271 |
for (IThreadGroupInfo groupInfo : getData().getGroupList()) { |
| 272 |
if (groupInfo.getPid().equals(finalGroupId)) { |
| 273 |
fDebuggedProcessesAndNames.put(finalInfNo, groupInfo.getDesciption()); |
| 274 |
} |
| 275 |
} |
| 276 |
} |
| 277 |
else { |
| 278 |
// Looks like this gdb doesn't truly support |
| 279 |
// "-list-thread-groups --available". Get the |
| 280 |
// process list natively if we're debugging locally |
| 281 |
IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class); |
| 282 |
if (backend.getSessionType() == SessionType.LOCAL) { |
| 283 |
IProcessList list = null; |
| 284 |
try { |
| 285 |
list = CCorePlugin.getDefault().getProcessList(); |
| 286 |
int groupId_int = Integer.parseInt(finalGroupId); |
| 287 |
for (IProcessInfo procInfo : list.getProcessList()) { |
| 288 |
if (procInfo.getPid() == groupId_int) { |
| 289 |
fDebuggedProcessesAndNames.put(finalGroupId, procInfo.getName()); |
| 290 |
} |
| 291 |
} |
| 292 |
} catch (CoreException e) { |
| 293 |
} |
| 294 |
} |
| 295 |
} |
| 296 |
} |
| 297 |
}); |
| 298 |
} else if ("thread-group-exited".equals(miEvent)) { //$NON-NLS-1$ |
| 299 |
// GDB is no longer debugging this process. Remove it from our list. |
| 300 |
fDebuggedProcessesAndNames.remove(groupId); |
| 301 |
|
| 302 |
// Remove any entries for that group from our thread to group map |
| 303 |
// When detaching from a group, we won't have received any thread-exited event |
| 304 |
// but we don't want to keep those entries. |
| 305 |
if (fThreadToGroupMap.containsValue(groupId)) { |
| 306 |
Iterator<Map.Entry<String, String>> iterator = fThreadToGroupMap.entrySet().iterator(); |
| 307 |
while (iterator.hasNext()){ |
| 308 |
if (iterator.next().getValue().equals(groupId)) { |
| 309 |
iterator.remove(); |
| 310 |
} |
| 311 |
} |
| 312 |
} |
| 313 |
} |
| 314 |
} |
| 315 |
} |
| 316 |
} |
| 317 |
} |
| 318 |
} |
| 319 |
*/ |
| 320 |
|
| 321 |
} |
| 322 |
|