diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/breakpoints/GdbBreakpointVMProvider.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/breakpoints/GdbBreakpointVMProvider.java index aaf22db4549..16083ce545b 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/breakpoints/GdbBreakpointVMProvider.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb.ui/src/org/eclipse/cdt/dsf/gdb/internal/ui/viewmodel/breakpoints/GdbBreakpointVMProvider.java @@ -13,6 +13,7 @@ package org.eclipse.cdt.dsf.gdb.internal.ui.viewmodel.breakpoints; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -24,16 +25,19 @@ import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.DsfRunnable; import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.debug.service.IBreakpoints; import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext; +import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMData; import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext; import org.eclipse.cdt.dsf.debug.service.IBreakpointsExtension; import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext; import org.eclipse.cdt.dsf.debug.ui.viewmodel.breakpoints.BreakpointVMProvider; import org.eclipse.cdt.dsf.gdb.IGdbDebugPreferenceConstants; import org.eclipse.cdt.dsf.gdb.internal.ui.GdbUIPlugin; +import org.eclipse.cdt.dsf.mi.service.IMIContainerDMContext; import org.eclipse.cdt.dsf.mi.service.IMIExecutionDMContext; import org.eclipse.cdt.dsf.mi.service.MIBreakpointDMData; import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager; @@ -103,16 +107,16 @@ public class GdbBreakpointVMProvider extends BreakpointVMProvider { @Override protected void calcFileteredBreakpoints( final DataRequestMonitor rm ) { if ( Boolean.TRUE.equals( getPresentationContext().getProperty( IBreakpointUIConstants.PROP_BREAKPOINTS_FILTER_SELECTION ) ) ) { - if (fUseAggressiveBpFilter) { + if ( fUseAggressiveBpFilter ) { // Aggressive filtering of breakpoints. Only return bps that are installed on the target. IBreakpointsTargetDMContext bpContext = null; - IMIExecutionDMContext threadContext = null; + IExecutionDMContext execContext = null; ISelection debugContext = getDebugContext(); if ( debugContext instanceof IStructuredSelection ) { - Object element = ((IStructuredSelection)debugContext).getFirstElement(); + Object element = ( (IStructuredSelection)debugContext ).getFirstElement(); if ( element instanceof IDMVMContext ) { bpContext = DMContexts.getAncestorOfType( ((IDMVMContext)element).getDMContext(), IBreakpointsTargetDMContext.class ); - threadContext = DMContexts.getAncestorOfType( ((IDMVMContext)element).getDMContext(), IMIExecutionDMContext.class ); + execContext = DMContexts.getAncestorOfType( ((IDMVMContext)element).getDMContext(), IExecutionDMContext.class ); } } @@ -127,17 +131,17 @@ public class GdbBreakpointVMProvider extends BreakpointVMProvider { return; } - getInstalledBreakpoints( bpContext, threadContext, rm ); + getInstalledBreakpoints( bpContext, execContext, rm ); } else { // Original behavior of bp filtering. Return all bp of type ICBreakpoint IBreakpoint[] allBreakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(); - List filteredBPs = new ArrayList(allBreakpoints.length); + List filteredBPs = new ArrayList( allBreakpoints.length ); for (IBreakpoint bp : allBreakpoints) { - if (bp instanceof ICBreakpoint && bp.getModelIdentifier().equals(CDebugCorePlugin.PLUGIN_ID)) { - filteredBPs.add(bp); + if ( bp instanceof ICBreakpoint && bp.getModelIdentifier().equals( CDebugCorePlugin.PLUGIN_ID ) ) { + filteredBPs.add( bp ); } } - rm.done( filteredBPs.toArray(new IBreakpoint[filteredBPs.size()]) ); + rm.done( filteredBPs.toArray( new IBreakpoint[filteredBPs.size()]) ); } } else { @@ -221,7 +225,7 @@ public class GdbBreakpointVMProvider extends BreakpointVMProvider { return StructuredSelection.EMPTY; } - void getInstalledBreakpoints( final IBreakpointsTargetDMContext targetContext, final IMIExecutionDMContext threadContext, final DataRequestMonitor rm ) { + private void getInstalledBreakpoints( final IBreakpointsTargetDMContext targetContext, final IExecutionDMContext execContext, final DataRequestMonitor rm ) { try { fSession.getExecutor().execute( new DsfRunnable() { @@ -237,7 +241,7 @@ public class GdbBreakpointVMProvider extends BreakpointVMProvider { rm.done(); return; } - bpService.getBreakpoints( targetContext, new DataRequestMonitor( fSession.getExecutor(), rm ) { + bpService.getBreakpoints( targetContext, new DataRequestMonitor( fSession.getExecutor(), rm ) { @Override protected void handleSuccess() { @@ -267,7 +271,7 @@ public class GdbBreakpointVMProvider extends BreakpointVMProvider { for ( final IBreakpointDMContext bpCtx : getData() ) { bpService.getBreakpointDMData( bpCtx, - new DataRequestMonitor( ImmediateExecutor.getInstance(), crm ) { + new DataRequestMonitor( ImmediateExecutor.getInstance(), crm ) { /* (non-Javadoc) * @see org.eclipse.cdt.dsf.concurrent.RequestMonitor#handleSuccess() @@ -276,10 +280,19 @@ public class GdbBreakpointVMProvider extends BreakpointVMProvider { protected void handleSuccess() { if ( getData() instanceof MIBreakpointDMData ) { MIBreakpointDMData data = (MIBreakpointDMData)getData(); - if ( !data.isPending() && isThreadBreakpoint( threadContext, data )) { - IBreakpoint bp = bpManager.findPlatformBreakpoint( bpCtx ); - if ( bp != null ) - bps.add( bp ); + if ( !data.isPending() ) { + bpBelongsToContext( execContext, data, new ImmediateDataRequestMonitor(crm) { + @Override + protected void handleSuccess() { + if (getData()) { + IBreakpoint bp = bpManager.findPlatformBreakpoint( bpCtx ); + if ( bp != null ) + bps.add( bp ); + } + crm.done(); + } + }); + return; } } crm.done(); @@ -306,25 +319,55 @@ public class GdbBreakpointVMProvider extends BreakpointVMProvider { } } - private boolean isThreadBreakpoint( IMIExecutionDMContext threadContext, MIBreakpointDMData data ) { - if ( threadContext == null || data.getThreadId() == null || data.getThreadId().length() == 0 ) { - // Ignore threads - return true; + private void bpBelongsToContext( IExecutionDMContext execContext, final MIBreakpointDMData data, final DataRequestMonitor rm ) { + if ( execContext == null ) { + // No execution context so accept all breakpoints + rm.done( true ); + return; } - - int threadId = threadContext.getThreadId(); - try { - int bpThreadId = Integer.parseInt( data.getThreadId() ); - if ( bpThreadId == 0 ) - return true; - return ( threadId == bpThreadId ); + + // First check if a thread is selected as the context. In that case, we only want to show breakpoints that + // are applicable to that thread. + IMIExecutionDMContext threadContext = DMContexts.getAncestorOfType( execContext, IMIExecutionDMContext.class ); + if ( threadContext != null ) { + // A thread is selected. Now make sure this breakpoint is assigned to this thread. + if ( data.getThreadId() != null && data.getThreadId().length() > 0 ) { + try { + int bpThreadId = Integer.parseInt( data.getThreadId() ); + // A threadId of 0 means all threads of this process. We therefore will have to check + // if this breakpoint applies to the process that is selected. But if the threadId is not 0 + // we simply make sure we have the right thread selected. + if ( bpThreadId != 0 ) { + rm.done( threadContext.getThreadId() == bpThreadId ); + return; + } + } + catch( NumberFormatException e ) { + assert false; + GdbUIPlugin.getDefault().getLog().log( new Status( + IStatus.ERROR, + GdbUIPlugin.getUniqueIdentifier(), + "Invalid breakpoint thread id" ) ); //$NON-NLS-1$ + rm.done( true ); + return; + } + } + } + + // If we get here it is that the breakpoint is not assigned to a single thread. + // We therefore make sure the breakpoint is applicable to the selected process. + final IMIContainerDMContext containerContext = DMContexts.getAncestorOfType( execContext, IMIContainerDMContext.class ); + if ( containerContext != null ) { + if ( data.getGroupIds() != null ) { + List groupIds = Arrays.asList( data.getGroupIds() ); + rm.done( groupIds.contains( containerContext.getGroupId() ) ); + } else { + // This happens if we are debugging a single process, so all breakpoints apply. + rm.done( true ); + } + } else { + // Accept breakpoint + rm.done( true ); } - catch( NumberFormatException e ) { - GdbUIPlugin.getDefault().getLog().log( new Status( - IStatus.ERROR, - GdbUIPlugin.getUniqueIdentifier(), - "Invalid breakpoint thread id" ) ); //$NON-NLS-1$ - } - return true; } } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_2.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_2.java index 088c3591b20..0f2a9314ce0 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_2.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/gdb/service/GDBBreakpoints_7_2.java @@ -8,7 +8,9 @@ * Contributors: * Ericsson - Initial API and implementation * Marc Khouzam (Ericsson) - Support for fast tracepoints (Bug 346320) + * Marc Khouzam (Ericsson) - Fetch groupIds when getting breakpoints (Bug 360735) *******************************************************************************/ + package org.eclipse.cdt.dsf.gdb.service; import java.util.HashMap; @@ -27,7 +29,10 @@ import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.mi.service.IMICommandControl; import org.eclipse.cdt.dsf.mi.service.MIBreakpointDMData; import org.eclipse.cdt.dsf.mi.service.MIBreakpoints; +import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoBreakInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakInsertInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakListInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIBreakpoint; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; @@ -89,6 +94,73 @@ public class GDBBreakpoints_7_2 extends GDBBreakpoints_7_0 super.shutdown(requestMonitor); } + /** + * {@inheritDoc} + * + * Starting with GDB 7.2, also provides information about which process each breakpoint applies to. + */ + @Override + public void getBreakpoints(final IBreakpointsTargetDMContext context, final DataRequestMonitor drm) + { + // Validate the context + if (context == null) { + drm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, UNKNOWN_EXECUTION_CONTEXT, null)); + drm.done(); + return; + } + + // Select the breakpoints context map + // If it doesn't exist then no breakpoint was ever inserted for this breakpoint space. + // In that case, return an empty list. + final Map breakpointContext = getBreakpointMap(context); + if (breakpointContext == null) { + drm.setData(new IBreakpointDMContext[0]); + drm.done(); + return; + } + + // Execute the command + fConnection.queueCommand(fConnection.getCommandFactory().createMIBreakList(context), + new DataRequestMonitor(getExecutor(), drm) { + @Override + protected void handleSuccess() { + final MIBreakpoint[] breakpoints = getData().getMIBreakpoints(); + + // Also fetch the information about which breakpoint belongs to which + // process. We currently can only obtain this information from the CLI + // command. This information is needed for breakpoint filtering. + // Bug 360735 + fConnection.queueCommand(fConnection.getCommandFactory().createCLIInfoBreak(context), + new ImmediateDataRequestMonitor(drm) { + @Override + protected void handleSuccess() { + Map groupIdMap = getData().getBreakpointToGroupMap(); + + // Refresh the breakpoints map and format the result + breakpointContext.clear(); + IBreakpointDMContext[] result = new IBreakpointDMContext[breakpoints.length]; + for (int i = 0; i < breakpoints.length; i++) { + MIBreakpointDMData breakpointData = new MIBreakpointDMData(breakpoints[i]); + + // Now fill in the thread-group information into the breakpoint data + // It is ok to get null. For example, pending breakpoints are not + // associated to a thread-group; also, when debugging a single process, + // the thread-group list is empty. + int reference = breakpointData.getReference(); + String[] groupIds = groupIdMap.get(reference); + breakpointData.setGroupIds(groupIds); + + result[i] = new MIBreakpointDMContext(GDBBreakpoints_7_2.this, new IDMContext[] { context }, reference); + breakpointContext.put(reference, breakpointData); + } + drm.setData(result); + drm.done(); + } + }); + } + }); + } + private void setTracepointMode() { ILaunch launch = (ILaunch)getSession().getModelAdapter(ILaunch.class); String tpMode = IGDBLaunchConfigurationConstants.DEBUGGER_TRACEPOINT_MODE_DEFAULT; diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointDMData.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointDMData.java index e9e311cfc34..bff232cda88 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointDMData.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIBreakpointDMData.java @@ -269,6 +269,10 @@ public class MIBreakpointDMData implements IBreakpointDMData { return fBreakpoint.isEnabled(); } + /////////////////////////////////////////////////////////////////////////// + // MIBreakpointDMData + /////////////////////////////////////////////////////////////////////////// + /** * @since 3.0 */ @@ -283,10 +287,6 @@ public class MIBreakpointDMData implements IBreakpointDMData { return fBreakpoint.getCommands(); } - /////////////////////////////////////////////////////////////////////////// - // MIBreakpointDMData - /////////////////////////////////////////////////////////////////////////// - public int getNumber() { return fBreakpoint.getNumber(); } @@ -295,6 +295,16 @@ public class MIBreakpointDMData implements IBreakpointDMData { return fBreakpoint.getThreadId(); } + /** @since 4.2 */ + public String[] getGroupIds() { + return fBreakpoint.getGroupIds(); + } + + /** @since 4.2 */ + public void setGroupIds(String[] groups) { + fBreakpoint.setGroupIds(groups); + } + public boolean isTemporary() { return fBreakpoint.isTemporary(); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java index c10c43b7581..865f1b8c9fd 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/CommandFactory.java @@ -43,6 +43,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.CLIAttach; import org.eclipse.cdt.dsf.mi.service.command.commands.CLICatch; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIDetach; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIExecAbort; +import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoBreak; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoProgram; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoSharedLibrary; import org.eclipse.cdt.dsf.mi.service.command.commands.CLIInfoThreads; @@ -167,6 +168,7 @@ import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowAttributes; import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarShowFormat; import org.eclipse.cdt.dsf.mi.service.command.commands.MIVarUpdate; import org.eclipse.cdt.dsf.mi.service.command.output.CLICatchInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoBreakInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoProgramInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoSharedLibraryInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoThreadsInfo; @@ -241,6 +243,16 @@ public class CommandFactory { return new CLIExecAbort(ctx); } + /** @since 4.2 */ + public ICommand createCLIInfoBreak(IDMContext ctx) { + return new CLIInfoBreak(ctx); + } + + /** @since 4.2 */ + public ICommand createCLIInfoBreak(IDMContext ctx, int bpRef) { + return new CLIInfoBreak(ctx, bpRef); + } + public ICommand createCLIInfoProgram(IContainerDMContext ctx) { return new CLIInfoProgram(ctx); } diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInfoBreak.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInfoBreak.java new file mode 100644 index 00000000000..cbeb9707b69 --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/commands/CLIInfoBreak.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2012 Ericsson 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: + * Marc Khouzam (Ericsson) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service.command.commands; + +import org.eclipse.cdt.dsf.datamodel.IDMContext; +import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoBreakInfo; +import org.eclipse.cdt.dsf.mi.service.command.output.MIOutput; + +/** + * 'info break [BP_REFERENCE] + * + * will return information about the specified breakpoint. If no breakpoint is + * specified, it will return information about all breakpoints. + * We use it to find out to which inferior a breakpoint is applicable. + * This information is not available from -break-list or -break-info until GDB 7.6. + * + * @since 4.2 + */ +public class CLIInfoBreak extends CLICommand { + + private static final String INFO_BREAK = "info break"; //$NON-NLS-1$ + + public CLIInfoBreak(IDMContext ctx) { + super(ctx, INFO_BREAK); + }; + + public CLIInfoBreak(IDMContext ctx, int bpReference) { + super(ctx, INFO_BREAK + Integer.toString(bpReference)); + } + + @Override + public CLIInfoBreakInfo getResult(MIOutput MIresult) { + return new CLIInfoBreakInfo(MIresult); + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/CLIInfoBreakInfo.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/CLIInfoBreakInfo.java new file mode 100644 index 00000000000..04936c1e85b --- /dev/null +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/CLIInfoBreakInfo.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2012 Ericsson 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: + * Marc Khouzam (Ericsson) - Initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.dsf.mi.service.command.output; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 'info break [BP_REFERENCE] will return information about + * the specified breakpoint. We use it to find out to which + * inferiors a breakpoint is applicable. + * + * sample output: + * + * (gdb) info break + * Num Type Disp Enb Address What + * 1 breakpoint keep y + * 1.1 y 0x08048533 in main() at loopfirst.cc:8 inf 2 + * 1.2 y 0x08048533 in main() at loopfirst.cc:8 inf 1 + * 2 breakpoint keep y + * 2.1 y 0x08048553 in main() at loopfirst.cc:9 inf 2 + * 2.2 y 0x08048553 in main() at loopfirst.cc:9 inf 1 + * + * If only one inferior is being debugged there is not mention of the inferior: + * (gdb) info break + * Num Type Disp Enb Address What + * 1 breakpoint keep y 0x08048533 in main() at loopfirst.cc:8 + * 2 breakpoint keep y 0x08048553 in main() at loopfirst.cc:9 + * + * Note that the below output is theoretically possible looking at GDB's code but + * I haven't figured out a way to trigger it. Still, we should be prepared for it: + * (gdb) info break + * Num Type Disp Enb Address What + * 1 breakpoint keep y + * 1.1 y 0x08048533 in main() at loopfirst.cc:8 inf 3, 2 + * 1.2 y 0x08048533 in main() at loopfirst.cc:8 inf 2, 1 + * 2 breakpoint keep y + * 2.1 y 0x08048553 in main() at loopfirst.cc:9 inf 2, 1 + * 2.2 y 0x08048553 in main() at loopfirst.cc:9 inf 3, 2, 1 + * + * @since 4.2 + */ +public class CLIInfoBreakInfo extends MIInfo { + + private Map fBreakpointToGroupMap = new HashMap(); + + public CLIInfoBreakInfo(MIOutput out) { + super(out); + parse(); + } + + /** + * Returns the map of breakpoint to groupId array indicating to which thread-group + * each breakpoint applies. If there is only a single thread-group being debugged, an + * empty map will be returned. + */ + public Map getBreakpointToGroupMap() { + return fBreakpointToGroupMap; + } + + protected void parse() { + final String INFERIOR_PREFIX = " inf "; //$NON-NLS-1$ + if (isDone()) { + MIOutput out = getMIOutput(); + for (MIOOBRecord oob : out.getMIOOBRecords()) { + if (oob instanceof MIConsoleStreamOutput) { + String line = ((MIConsoleStreamOutput)oob).getString().trim(); + int loc = line.indexOf(INFERIOR_PREFIX); + if (loc >= 0) { + // Get the breakpoint id by extracting the first element before a white space + // or before a period. We can set a limit of 2 since we only need the first element + String bpIdStr = line.split("[\\s\\.]", 2)[0]; //$NON-NLS-1$ + int bpId = 0; + try { + bpId = Integer.parseInt(bpIdStr); + } catch (NumberFormatException e) { + assert false; + } + + String[] groups = fBreakpointToGroupMap.get(bpId); + Set groupIdList = new HashSet(); + if (groups != null) { + // Since we already know about this breakpoint id we must retain the list + // we have been building + groupIdList.addAll(Arrays.asList(groups)); + } + + // Get the comma-separated list of inferiors + // Split the list into individual ids + String inferiorIdStr = line.substring(loc + INFERIOR_PREFIX.length()).trim(); + for (String id : inferiorIdStr.split(",")) { //$NON-NLS-1$ + // Add the 'i' prefix as GDB does for MI commands + groupIdList.add("i" + id.trim()); //$NON-NLS-1$ + } + + fBreakpointToGroupMap.put(bpId, groupIdList.toArray(new String[groupIdList.size()])); + } + } + } + } + } +} diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIBreakpoint.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIBreakpoint.java index 310901feb1c..ad25af95923 100644 --- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIBreakpoint.java +++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/command/output/MIBreakpoint.java @@ -11,10 +11,14 @@ * Ericsson - Modified for the breakpoint service * Ericsson - Added Tracepoint support (284286) * Abeer Bagul (Tensilica) - Differentiate between hw breakpoint and watchpoint + * Marc Khouzam (Ericsson) - Add 'thread-group' field (bug 360735) *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service.command.output; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.StringTokenizer; import org.eclipse.cdt.dsf.gdb.internal.tracepointactions.TracepointActionManager; @@ -105,6 +109,13 @@ public class MIBreakpoint { */ private boolean pending; + /** + * The list of groupIds to which this breakpoint applies. + * This field is only reported by MI starting with GDB 7.6. + * null will be returned if this field is not present. + */ + private String[] groupIds; + public MIBreakpoint() { } @@ -134,6 +145,9 @@ public class MIBreakpoint { isCatchpoint = other.isCatchpoint; catchpointType = other.catchpointType; pending = other.pending; + if (other.groupIds != null) { + groupIds = Arrays.copyOf(other.groupIds, other.groupIds.length); + } } public MIBreakpoint(MITuple tuple) { @@ -409,6 +423,25 @@ public class MIBreakpoint { return pending; } + /** + * Returns the thread-groups to which this breakpoint applies. + * Returns null if the data is not known. + * + * @since 4.2 + */ + public String[] getGroupIds() { + return groupIds; + } + + /** + * Sets the list of thread-groups to which this breakpoint applies. + * + * @since 4.2 + */ + public void setGroupIds(String[] groups) { + groupIds = groups; + } + // Parse the result string void parse(MITuple tuple) { MIResult[] results = tuple.getMIResults(); @@ -504,6 +537,10 @@ public class MIBreakpoint { if (value instanceof MITuple) { parseCommands((MITuple)value); } + } else if (var.equals("thread-group")) { //$NON-NLS-1$ + if (value instanceof MIList) { + parseGroups((MIList)value); + } } } } @@ -524,4 +561,17 @@ public class MIBreakpoint { setCommands(cmds.toString()); } + + private void parseGroups(MIList list) { + List groups = new ArrayList(); + + MIValue[] values = list.getMIValues(); + for (int i = 0; i < values.length; i++) { + if (values[i] instanceof MIConst) { + groups.add(((MIConst)values[i]).getCString()); + } + } + + groupIds = groups.toArray(new String[groups.size()]); + } }