1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

[274135] Changes to support GDB HEAD, to lead to the proper support of GDB 7.0

This commit is contained in:
Marc Khouzam 2009-05-06 17:50:13 +00:00
parent f9f6f4d46a
commit 2d2e01d6f4
4 changed files with 154 additions and 96 deletions

View file

@ -11,6 +11,7 @@
package org.eclipse.cdt.dsf.gdb.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
@ -341,12 +342,21 @@ public class GDBProcesses_7_0 extends AbstractDsfService
private Map<String, String> fThreadToGroupMap = new HashMap<String, String>();
private IGDBControl fCommandControl;
private IGDBBackend fBackend;
// A cache for commands about the threadGroups
private CommandCache fContainerCommandCache;
//A cache for commands about the threads
private CommandCache fThreadCommandCache;
// A temporary cache to avoid using -list-thread-groups --available more than once at the same time.
// We cannot cache this command because it lists all available processes, which can
// change at any time. However, it is inefficient to send more than one of this command at
// the same time. This cache will help us avoid that. The idea is that we cache the command,
// but as soon as it returns, we clear the cache. So the cache will only trigger for those
// overlapping situations.
private CommandCache fListThreadGroupsAvailableCache;
// A map of process id to process names. It is filled when we get all the processes that are running
private Map<String, String> fProcessNames = new HashMap<String, String>();
@ -384,10 +394,15 @@ public class GDBProcesses_7_0 extends AbstractDsfService
private void doInitialize(RequestMonitor requestMonitor) {
fCommandControl = getServicesTracker().getService(IGDBControl.class);
fBackend = getServicesTracker().getService(IGDBBackend.class);
fContainerCommandCache = new CommandCache(getSession(), fCommandControl);
fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true);
fThreadCommandCache = new CommandCache(getSession(), fCommandControl);
fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true);
fListThreadGroupsAvailableCache = new CommandCache(getSession(), fCommandControl);
fListThreadGroupsAvailableCache.setContextAvailable(fCommandControl.getContext(), true);
getSession().addServiceEventListener(this, null);
fCommandControl.addEventListener(this);
@ -447,6 +462,21 @@ public class GDBProcesses_7_0 extends AbstractDsfService
public IMIContainerDMContext createContainerContextFromThreadId(ICommandControlDMContext controlDmc, String threadId) {
String groupId = fThreadToGroupMap.get(threadId);
if (groupId == null) {
// this can happen if the threadId was 'all'
// In such a case, we choose the first process we find
// This works when we run a single process
// but will break for multi-process!!!
if (fThreadToGroupMap.isEmpty()) {
groupId = MIProcesses.UNIQUE_GROUP_ID;
} else {
Collection<String> values = fThreadToGroupMap.values();
for (String value : values) {
groupId = value;
break;
}
}
}
IProcessDMContext processDmc = createProcessContext(controlDmc, groupId);
return createContainerContext(processDmc, groupId);
}
@ -471,42 +501,58 @@ public class GDBProcesses_7_0 extends AbstractDsfService
public void getExecutionData(IThreadDMContext dmc, final DataRequestMonitor<IThreadDMData> rm) {
if (dmc instanceof IMIProcessDMContext) {
final String id = ((IMIProcessDMContext)dmc).getProcId();
String name = fProcessNames.get(id);
if (name == null) {
// We don't have the name yet. Maybe we didn't fetch names yet,
// or maybe this is a new process
// This is not very efficient, but GDB does not provide a way to get the name
// of a single process.
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
fCommandControl.queueCommand(
new MIListThreadGroups(controlDmc, true),
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {
@Override
protected void handleCompleted() {
String name = null;
if (isSuccess()) {
for (IThreadGroupInfo groupInfo : getData().getGroupList()) {
fProcessNames.put(groupInfo.getPid(), groupInfo.getName());
if (groupInfo.getPid().equals(id)) {
name = groupInfo.getName();
if (fBackend.getSessionType() == SessionType.CORE) {
// For the Core session, the process is no longer running.
// Therefore, we cannot get its name with the -list-thread-groups command
// Instead, we take it from the binary we are using.
String name = fBackend.getProgramPath().lastSegment();
// Also, the pid we get from GDB is 1, which is not correct.
// I haven't found a good way to get the pid yet, so let's not show it.
rm.setData(new MIThreadDMData(name, null));
rm.done();
} else {
final String id = ((IMIProcessDMContext)dmc).getProcId();
String name = fProcessNames.get(id);
if (name == null) {
// We don't have the name yet. Maybe we didn't fetch names yet,
// or maybe this is a new process
// This is not very efficient, but GDB does not provide a way to get the name
// of a single process.
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
fListThreadGroupsAvailableCache.execute(
new MIListThreadGroups(controlDmc, true),
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {
@Override
protected void handleCompleted() {
// We cannot actually cache this command since the process
// list may change. But this cache allows to avoid overlapping
// sending of this command.
fListThreadGroupsAvailableCache.reset();
String name = null;
if (isSuccess()) {
for (IThreadGroupInfo groupInfo : getData().getGroupList()) {
fProcessNames.put(groupInfo.getPid(), groupInfo.getName());
if (groupInfo.getPid().equals(id)) {
name = groupInfo.getName();
}
}
}
}
if (name == null) {
// We still don't have the name... weird.
// Don't go into an infinite loop by trying again, just give up
name = "Unknown name"; //$NON-NLS-1$
}
rm.setData(new MIThreadDMData(name, id));
rm.done();
}
});
} else {
rm.setData(new MIThreadDMData(name, id));
rm.done();
if (name == null) {
// We still don't have the name... weird.
// Don't go into an infinite loop by trying again, just give up
name = "Unknown name"; //$NON-NLS-1$
}
rm.setData(new MIThreadDMData(name, id));
rm.done();
}
});
} else {
rm.setData(new MIThreadDMData(name, id));
rm.done();
}
}
} else if (dmc instanceof MIThreadDMC) {
final MIThreadDMC threadDmc = (MIThreadDMC)dmc;
@ -554,15 +600,28 @@ public class GDBProcesses_7_0 extends AbstractDsfService
rm.done();
}
public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
private boolean doIsDebuggerAttachSupported() {
IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class);
rm.setData(backend.getIsAttachSession());
if (backend != null) {
return backend.getIsAttachSession();
}
return false;
}
public void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
rm.setData(doIsDebuggerAttachSupported());
rm.done();
}
public void attachDebuggerToProcess(final IProcessDMContext procCtx, final DataRequestMonitor<IDMContext> rm) {
if (procCtx instanceof IMIProcessDMContext) {
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, ICommandControlDMContext.class);
if (!doIsDebuggerAttachSupported()) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Attach not supported.", null)); //$NON-NLS-1$
rm.done();
return;
}
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(procCtx, ICommandControlDMContext.class);
fCommandControl.queueCommand(
new MITargetAttach(controlDmc, ((IMIProcessDMContext)procCtx).getProcId()),
new DataRequestMonitor<MIInfo>(getExecutor(), rm) {
@ -580,19 +639,33 @@ public class GDBProcesses_7_0 extends AbstractDsfService
rm.done();
}
}
public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
private boolean doCanDetachDebuggerFromProcess() {
IGDBBackend backend = getServicesTracker().getService(IGDBBackend.class);
rm.setData(backend.getIsAttachSession() && fCommandControl.isConnected());
if (backend != null) {
return backend.getIsAttachSession() && fCommandControl.isConnected();
}
return false;
}
public void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm) {
rm.setData(doCanDetachDebuggerFromProcess());
rm.done();
}
public void detachDebuggerFromProcess(final IDMContext dmc, final RequestMonitor rm) {
ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
IMIProcessDMContext procDmc = DMContexts.getAncestorOfType(dmc, IMIProcessDMContext.class);
if (controlDmc != null && procDmc != null) {
fCommandControl.queueCommand(
if (!doCanDetachDebuggerFromProcess()) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Detach not supported.", null)); //$NON-NLS-1$
rm.done();
return;
}
fCommandControl.queueCommand(
new MITargetDetach(controlDmc, procDmc.getProcId()),
new DataRequestMonitor<MIInfo>(getExecutor(), rm));
} else {
@ -619,38 +692,29 @@ public class GDBProcesses_7_0 extends AbstractDsfService
}
public void getProcessesBeingDebugged(final IDMContext dmc, final DataRequestMonitor<IDMContext[]> rm) {
// MIInferiorProcess inferiorProcess = fCommandControl.getInferiorProcess();
// if (fCommandControl.isConnected() &&
// inferiorProcess != null &&
// inferiorProcess.getState() != MIInferiorProcess.State.TERMINATED) {
final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
final IMIContainerDMContext containerDmc = DMContexts.getAncestorOfType(dmc, IMIContainerDMContext.class);
if (containerDmc != null) {
fThreadCommandCache.execute(
new MIListThreadGroups(controlDmc, containerDmc.getGroupId()),
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
rm.setData(makeExecutionDMCs(containerDmc, getData().getThreadInfo().getThreadList()));
rm.done();
}
});
} else {
fContainerCommandCache.execute(
new MIListThreadGroups(controlDmc),
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
rm.setData(makeContainerDMCs(controlDmc, getData().getGroupList()));
rm.done();
}
});
}
// } else {
// rm.setData(new IDMContext[0]);
// rm.done();
// }
final ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
final IMIContainerDMContext containerDmc = DMContexts.getAncestorOfType(dmc, IMIContainerDMContext.class);
if (containerDmc != null) {
fThreadCommandCache.execute(
new MIListThreadGroups(controlDmc, containerDmc.getGroupId()),
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
rm.setData(makeExecutionDMCs(containerDmc, getData().getThreadInfo().getThreadList()));
rm.done();
}
});
} else {
fContainerCommandCache.execute(
new MIListThreadGroups(controlDmc),
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {
@Override
protected void handleSuccess() {
rm.setData(makeContainerDMCs(controlDmc, getData().getGroupList()));
rm.done();
}
});
}
}
private IExecutionDMContext[] makeExecutionDMCs(IContainerDMContext containerDmc, MIThread[] threadInfos) {
@ -693,11 +757,16 @@ public class GDBProcesses_7_0 extends AbstractDsfService
if (controlDmc != null) {
// Don't cache this command since the list can change at any time.
fCommandControl.queueCommand(
fListThreadGroupsAvailableCache.execute(
new MIListThreadGroups(controlDmc, true),
new DataRequestMonitor<MIListThreadGroupsInfo>(getExecutor(), rm) {
@Override
protected void handleCompleted() {
// We cannot actually cache this command since the process
// list may change. But this cache allows to avoid overlapping
// sending of this command.
fListThreadGroupsAvailableCache.reset();
if (isSuccess()) {
for (IThreadGroupInfo groupInfo : getData().getGroupList()) {
fProcessNames.put(groupInfo.getPid(), groupInfo.getName());
@ -737,12 +806,7 @@ public class GDBProcesses_7_0 extends AbstractDsfService
}
public void terminate(IThreadDMContext thread, RequestMonitor rm) {
if (thread instanceof IMIProcessDMContext) {
fCommandControl.terminate(rm);
} else {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid process context.", null)); //$NON-NLS-1$
rm.done();
}
fCommandControl.terminate(rm);
}
@DsfServiceEventHandler
@ -757,7 +821,6 @@ public class GDBProcesses_7_0 extends AbstractDsfService
IProcessDMContext procDmc = e.getDMContext();
IMIContainerDMContext containerDmc = e.getGroupId() != null ? createContainerContext(procDmc, e.getGroupId()) : null;
getSession().dispatchEvent(new ContainerExitedDMEvent(containerDmc), getProperties());
}
@DsfServiceEventHandler
@ -777,8 +840,8 @@ public class GDBProcesses_7_0 extends AbstractDsfService
public void eventDispatched(ISuspendedDMEvent e) {
if (e instanceof IContainerSuspendedDMEvent) {
// This will happen in all-stop mode
fContainerCommandCache.setContextAvailable(e.getDMContext(), true);
fThreadCommandCache.setContextAvailable(e.getDMContext(), true);
fContainerCommandCache.setContextAvailable(fCommandControl.getContext(), true);
fThreadCommandCache.setContextAvailable(fCommandControl.getContext(), true);
} else {
// This will happen in non-stop mode
}
@ -843,13 +906,6 @@ public class GDBProcesses_7_0 extends AbstractDsfService
}
}
// Until GDB is officially supporting multi-process, we may not get
// a groupId. In this case, we are running single process and we'll
// need its groupId
if (groupId == null) {
groupId = MIProcesses.UNIQUE_GROUP_ID;
}
if ("thread-created".equals(miEvent)) { //$NON-NLS-1$
// Update the thread to groupId map with the new groupId
fThreadToGroupMap.put(threadId, groupId);

View file

@ -42,7 +42,7 @@ import org.eclipse.debug.core.ILaunchConfiguration;
public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
// This should eventually be "7.0" once GDB 7.0 is released
private static final String GDB_7_0_VERSION = "6.8.50.20081118"; //$NON-NLS-1$
private static final String GDB_7_0_VERSION = "6.8.50.20090218"; //$NON-NLS-1$
private final String fVersion;
@ -123,10 +123,7 @@ public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory {
@Override
protected IProcesses createProcessesService(DsfSession session) {
// Multi-process is not part of GDB HEAD yet,
// but is part of this very specific build.
// We'll need to change this when 7.0 is ready
if (fVersion.startsWith("6.8.50.20090218")) { //$NON-NLS-1$
if (GDB_7_0_VERSION.compareTo(fVersion) <= 0) {
return new GDBProcesses_7_0(session);
}
return new GDBProcesses(session);

View file

@ -289,7 +289,7 @@ public class MIRunControlEventProcessor_7_0
}
IExecutionDMContext execDmc = containerDmc;
if (threadId != null) {
if (threadId != null && !threadId.equals("all")) { //$NON-NLS-1$
IThreadDMContext threadDmc = procService.createThreadContext(procDmc, threadId);
execDmc = procService.createExecutionContext(containerDmc, threadDmc, threadId);
}

View file

@ -26,7 +26,8 @@ import org.eclipse.cdt.dsf.concurrent.Immutable;
* {id="162",type="process",description="name: JIM_TcpSetupHandlerProcess, type 555505, locked: N, system: N, state: Idle"},
* {id="165",type="process",description="name: JUnitProcess2_PT, type 1094608, locked: N, system: N, state: Idle"},
* {id="166",type="process",description="name: JUnitProcess_PT, type 1094605, locked: N, system: N, state: Idle"}]
*
*
* {id="3602",type="process",description="/usr/sbin/dhcdbd --system",user="root"}
* -list-thread-groups:
* ^done,groups=[{id="162",type="process",pid="162"}]
*
@ -66,6 +67,10 @@ public class MIListThreadGroupsInfo extends MIInfo {
Matcher matcher = pattern.matcher(desc);
if (matcher.find()) {
name = matcher.group(1);
} else {
// If we didn't get the form "name: " then we expect to have the form
// "/usr/sbin/dhcdbd --system"
name = desc.split("\\s", 2)[0]; //$NON-NLS-1$
}
return name;