/******************************************************************************* * Copyright (c) 2008, 2016 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: * Ericsson - initial API and implementation * Nokia - create and use backend service. * Onur Akdemir (TUBITAK BILGEM-ITI) - Multi-process debugging (Bug 237306) * Marc Khouzam (Ericsson) - Support for GDB 7.4 (Bug 367788) * Marc Khouzam (Ericsson) - Include IGDBHardware service for the multicore visualizer (Bug 335027) * Vladimir Prus (Mentor Graphics) - Support for OS resources. * Marc Khouzam (Ericsson) - Support for GDB 7.6 memory service * Marc Khouzam (Ericsson) - Support for GDB 7.4 trace control service * William Riley (Renesas) - Support for GDB 7.3 disassembly service (Bug 357270) * Marc Khouzam (Ericsson) - Support for GDB 7.4 processes service (Bug 389945) * Marc Khouzam (Ericsson) - Support dynamic printf in bp service 7.5 (Bug 400628) * Alvaro Sanchez-Leon (Ericsson) - Allow user to edit the register groups (Bug 235747) * Marc Dumais (Ericsson) - Update GDBHardwareAndOS service to take advantage of GDB providing CPU/core info (bug 464184) * Intel Corporation - Added Reverse Debugging BTrace support *******************************************************************************/ package org.eclipse.cdt.dsf.gdb.service; import org.eclipse.cdt.debug.core.CDebugCorePlugin; import org.eclipse.cdt.dsf.debug.service.AbstractDsfDebugServicesFactory; import org.eclipse.cdt.dsf.debug.service.IBreakpoints; import org.eclipse.cdt.dsf.debug.service.IDisassembly; import org.eclipse.cdt.dsf.debug.service.IDsfDebugServicesFactory; import org.eclipse.cdt.dsf.debug.service.IExpressions; import org.eclipse.cdt.dsf.debug.service.IMemory; import org.eclipse.cdt.dsf.debug.service.IModules; import org.eclipse.cdt.dsf.debug.service.IProcesses; import org.eclipse.cdt.dsf.debug.service.IRegisters; import org.eclipse.cdt.dsf.debug.service.IRunControl; import org.eclipse.cdt.dsf.debug.service.ISourceLookup; import org.eclipse.cdt.dsf.debug.service.IStack; import org.eclipse.cdt.dsf.debug.service.command.ICommandControl; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.gdb.internal.service.GDBFocusSynchronizer; import org.eclipse.cdt.dsf.gdb.internal.service.IGDBFocusSynchronizer; import org.eclipse.cdt.dsf.gdb.launching.GdbLaunch; import org.eclipse.cdt.dsf.gdb.launching.LaunchUtils; import org.eclipse.cdt.dsf.gdb.service.command.CommandFactory_6_8; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_0; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_12; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_2; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_4; import org.eclipse.cdt.dsf.gdb.service.command.GDBControl_7_7; import org.eclipse.cdt.dsf.mi.service.IMIBackend; import org.eclipse.cdt.dsf.mi.service.IMIExpressions; import org.eclipse.cdt.dsf.mi.service.MIBreakpoints; import org.eclipse.cdt.dsf.mi.service.MIBreakpointsManager; import org.eclipse.cdt.dsf.mi.service.MIBreakpointsSynchronizer; import org.eclipse.cdt.dsf.mi.service.MIDisassembly; import org.eclipse.cdt.dsf.mi.service.MIExpressions; import org.eclipse.cdt.dsf.mi.service.MIModules; import org.eclipse.cdt.dsf.mi.service.MIStack; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.cdt.dsf.service.IDsfService; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.osgi.util.NLS; public class GdbDebugServicesFactory extends AbstractDsfDebugServicesFactory { /** @since 4.0 */ public static final String GDB_6_8_VERSION = "6.8"; //$NON-NLS-1$ /** @since 4.0 */ public static final String GDB_7_0_VERSION = "7.0"; //$NON-NLS-1$ /** @since 4.0 */ public static final String GDB_7_1_VERSION = "7.1"; //$NON-NLS-1$ /** @since 4.0 */ public static final String GDB_7_2_VERSION = "7.2"; //$NON-NLS-1$ /** @since 4.1 */ public static final String GDB_7_2_1_VERSION = "7.2.1"; //$NON-NLS-1$ /** @since 4.1 */ public static final String GDB_7_3_VERSION = "7.3"; //$NON-NLS-1$ /** @since 4.1 */ public static final String GDB_7_4_VERSION = "7.4"; //$NON-NLS-1$ /** @since 4.2 */ public static final String GDB_7_5_VERSION = "7.5"; //$NON-NLS-1$ /** @since 4.2 */ public static final String GDB_7_6_VERSION = "7.5.50"; //$NON-NLS-1$ /** @since 4.4 */ public static final String GDB_7_7_VERSION = "7.7"; //$NON-NLS-1$ /** @since 4.8 */ public static final String GDB_7_10_VERSION = "7.10"; //$NON-NLS-1$ /** @since 5.2 */ public static final String GDB_7_12_VERSION = "7.12"; //$NON-NLS-1$ private final String fVersion; private final ILaunchConfiguration fConfiguration; /** @since 5.0 */ public GdbDebugServicesFactory(String version, ILaunchConfiguration config) { fVersion = version; fConfiguration = config; } /** * @deprecated Use {@link GdbDebugServicesFactory#GdbDebugServicesFactory(String, ILaunchConfiguration) */ @Deprecated public GdbDebugServicesFactory(String version) { fVersion = version; fConfiguration = null; } /** * Returns the launch configuration. This is useful for cases where the * service to use is dependent on the launch settings. * * @return configuration or <code>null</code> * @since 5.0 */ protected ILaunchConfiguration getConfiguration() { return fConfiguration; } /** * Returns true if the services should be created for non-stop mode. * @return <code>true</code> if services should be created for GDB non-stop * @since 5.0 */ protected boolean getIsNonStopMode() { ILaunchConfiguration configuration = getConfiguration(); if (configuration == null) { return false; } return LaunchUtils.getIsNonStopMode(configuration); } public String getVersion() { return fVersion; } @Override @SuppressWarnings("unchecked") public <V> V createService(Class<V> clazz, DsfSession session, Object ... optionalArguments) { if (MIBreakpointsManager.class.isAssignableFrom(clazz)) { return (V)createBreakpointManagerService(session); } else if (ICommandControl.class.isAssignableFrom(clazz)) { for (Object arg : optionalArguments) { if (arg instanceof ILaunchConfiguration) { return (V)createCommandControl(session, (ILaunchConfiguration)arg); } } } else if (IMIBackend.class.isAssignableFrom(clazz)) { for (Object arg : optionalArguments) { if (arg instanceof ILaunchConfiguration) { return (V)createBackendGDBService(session, (ILaunchConfiguration)arg); } } } else if (IGDBTraceControl.class.isAssignableFrom(clazz)) { for (Object arg : optionalArguments) { if (arg instanceof ILaunchConfiguration) { return (V)createTraceControlService(session, (ILaunchConfiguration)arg); } } } else if (IGDBHardwareAndOS.class.isAssignableFrom(clazz)) { for (Object arg : optionalArguments) { if (arg instanceof ILaunchConfiguration) { return (V)createHardwareAndOSService(session, (ILaunchConfiguration)arg); } } } else if (MIBreakpointsSynchronizer.class.isAssignableFrom(clazz)) { return (V)createBreakpointsSynchronizerService(session); } else if (IGDBFocusSynchronizer.class.isAssignableFrom(clazz)) { return (V)createFocusSynchronizerService(session); } return super.createService(clazz, session, optionalArguments); } protected MIBreakpointsManager createBreakpointManagerService(DsfSession session) { if (compareVersionWith(GDB_7_2_VERSION) >= 0) { return new GDBBreakpointsManager_7_2(session, CDebugCorePlugin.PLUGIN_ID); } if (compareVersionWith(GDB_7_0_VERSION) >= 0) { return new GDBBreakpointsManager_7_0(session, CDebugCorePlugin.PLUGIN_ID); } return new MIBreakpointsManager(session, CDebugCorePlugin.PLUGIN_ID); } @Override protected IBreakpoints createBreakpointService(DsfSession session) { if (compareVersionWith(GDB_7_7_VERSION) >= 0) { return new GDBBreakpoints_7_7(session); } if (compareVersionWith(GDB_7_6_VERSION) >= 0) { return new GDBBreakpoints_7_6(session); } if (compareVersionWith(GDB_7_4_VERSION) >= 0) { return new GDBBreakpoints_7_4(session); } // This service is available for GDB 7.2 but there is a pre-release of GDB that // supports the same features and has version of 6.8.50.20090414 if (compareVersionWith(GDB_7_2_VERSION) >= 0 || "6.8.50.20090414".equals(fVersion)) { //$NON-NLS-1$ return new GDBBreakpoints_7_2(session); } if (compareVersionWith(GDB_7_0_VERSION) >= 0) { return new GDBBreakpoints_7_0(session); } return new MIBreakpoints(session); } protected ICommandControl createCommandControl(DsfSession session, ILaunchConfiguration config) { if (compareVersionWith(GDB_7_12_VERSION) >= 0) { return new GDBControl_7_12(session, config, new CommandFactory_6_8()); } if (compareVersionWith(GDB_7_7_VERSION) >= 0) { return new GDBControl_7_7(session, config, new CommandFactory_6_8()); } if (compareVersionWith(GDB_7_4_VERSION) >= 0) { return new GDBControl_7_4(session, config, new CommandFactory_6_8()); } if (compareVersionWith(GDB_7_2_VERSION) >= 0) { return new GDBControl_7_2(session, config, new CommandFactory_6_8()); } if (compareVersionWith(GDB_7_0_VERSION) >= 0) { return new GDBControl_7_0(session, config, new CommandFactory_6_8()); } if (compareVersionWith(GDB_6_8_VERSION) >= 0) { return new GDBControl(session, config, new CommandFactory_6_8()); } return new GDBControl(session, config, new CommandFactory()); } protected IMIBackend createBackendGDBService(DsfSession session, ILaunchConfiguration lc) { if (compareVersionWith(GDB_7_12_VERSION) >= 0) { return new GDBBackend_7_12(session, lc); } return new GDBBackend(session, lc); } @Override protected IDisassembly createDisassemblyService(DsfSession session) { if (compareVersionWith(GDB_7_3_VERSION) >= 0) { return new GDBDisassembly_7_3(session); } return new MIDisassembly(session); } @Override protected IExpressions createExpressionService(DsfSession session) { // Replace the standard Expressions service with a version that supports pattern matching. // Pass in the original service which will be used as a delegate. // This way of doing things allows to keep the pattern matching aspect isolated // and easy to remove. IMIExpressions originialExpressionService = new MIExpressions(session); return new GDBPatternMatchingExpressions(session, originialExpressionService); } @Override protected IMemory createMemoryService(DsfSession session) { if (compareVersionWith(GDB_7_6_VERSION) >= 0) { return new GDBMemory_7_6(session); } if (compareVersionWith(GDB_7_0_VERSION) >= 0) { return new GDBMemory_7_0(session); } return new GDBMemory(session); } @Override protected IModules createModulesService(DsfSession session) { return new MIModules(session); } @Override protected IProcesses createProcessesService(DsfSession session) { if (compareVersionWith(GDB_7_12_VERSION) >= 0) { return new GDBProcesses_7_12(session); } if (compareVersionWith(GDB_7_10_VERSION) >= 0) { return new GDBProcesses_7_10(session); } if (compareVersionWith(GDB_7_4_VERSION) >= 0) { return new GDBProcesses_7_4(session); } if (compareVersionWith(GDB_7_3_VERSION) >= 0) { return new GDBProcesses_7_3(session); } if (compareVersionWith(GDB_7_2_1_VERSION) >= 0) { return new GDBProcesses_7_2_1(session); } if (compareVersionWith(GDB_7_2_VERSION) >= 0) { return new GDBProcesses_7_2(session); } if (compareVersionWith(GDB_7_1_VERSION) >= 0) { return new GDBProcesses_7_1(session); } if (compareVersionWith(GDB_7_0_VERSION) >= 0) { return new GDBProcesses_7_0(session); } return new GDBProcesses(session); } @Override protected IRegisters createRegistersService(DsfSession session) { return new GDBRegisters(session); } @Override protected IRunControl createRunControlService(DsfSession session) { // First check for the non-stop case if (getIsNonStopMode()) { if (compareVersionWith(GDB_7_2_VERSION) >= 0) { return new GDBRunControl_7_2_NS(session); } return new GDBRunControl_7_0_NS(session); } // Else, handle all-stop mode if (compareVersionWith(GDB_7_12_VERSION) >= 0) { return new GDBRunControl_7_12(session); } if (compareVersionWith(GDB_7_10_VERSION) >= 0) { return new GDBRunControl_7_10(session); } if (compareVersionWith(GDB_7_6_VERSION) >= 0) { return new GDBRunControl_7_6(session); } if (compareVersionWith(GDB_7_0_VERSION) >= 0) { return new GDBRunControl_7_0(session); } return new GDBRunControl(session); } @Override protected ISourceLookup createSourceLookupService(DsfSession session) { return new GDBSourceLookup(session); } @Override protected IStack createStackService(DsfSession session) { return new MIStack(session); } /** @since 3.0 */ protected IGDBTraceControl createTraceControlService(DsfSession session, ILaunchConfiguration config) { if (compareVersionWith(GDB_7_4_VERSION) >= 0) { return new GDBTraceControl_7_4(session, config); } // This service is available for GDB 7.2 but there is a pre-release of GDB that // supports the same features and has version of 6.8.50.20090414 if (compareVersionWith(GDB_7_2_VERSION) >= 0 || "6.8.50.20090414".equals(fVersion)) { //$NON-NLS-1$ return new GDBTraceControl_7_2(session, config); } // There is currently no implementation of the TraceControl service before GDB 7.2 // It could be done with restricted functionality for GDB 7.1 and maybe even 7.0 // but the service would have to be properly coded, as some MI commands don't exists // in those older GDB versions. Also, gdbserver only supports tracing starting with 7.2 return null; } /** @since 4.1 */ protected IGDBHardwareAndOS createHardwareAndOSService(DsfSession session, ILaunchConfiguration config) { if (compareVersionWith(GDB_7_10_VERSION) >= 0) { return new GDBHardwareAndOS_7_10(session); } if (compareVersionWith(GDB_7_5_VERSION) >= 0) { return new GDBHardwareAndOS_7_5(session); } return new GDBHardwareAndOS(session); } /** * @since 4.2 */ protected MIBreakpointsSynchronizer createBreakpointsSynchronizerService(DsfSession session) { return new MIBreakpointsSynchronizer(session); } /** * @since 5.2 */ protected IGDBFocusSynchronizer createFocusSynchronizerService(DsfSession session) { return new GDBFocusSynchronizer(session); } /** * Compares the GDB version of the current debug session with the one specified by * parameter 'version'. Returns -1, 0, or 1 if the current version is less than, * equal to, or greater than the specified version, respectively. * @param version The version to compare with * @return -1, 0, or 1 if the current version is less than, equal to, or greater than * the specified version, respectively. * @since 4.8 */ protected int compareVersionWith(String version) { return LaunchUtils.compareVersions(getVersion(), version); } /** * A static method that will compare the version of GDB for the specified session and * the minimum GDB version required by the caller. A warning will be logged if the * running version is not sufficient. * * @param session The debug session running GDB * @param minVersion The minimum version of GDB required * @param service The service requesting the check. * * @since 4.8 */ public static void validateGdbVersion(DsfSession session, String minVersion, IDsfService service) { ILaunch launch = (ILaunch)session.getModelAdapter(ILaunch.class); if (launch instanceof GdbLaunch) { IDsfDebugServicesFactory servicesFactory = ((GdbLaunch)launch).getServiceFactory(); if (servicesFactory instanceof GdbDebugServicesFactory) { String version = ((GdbDebugServicesFactory)servicesFactory).getVersion(); if (LaunchUtils.compareVersions(minVersion, version) > 0) { assert false; GdbPlugin.log( new Status( IStatus.WARNING, GdbPlugin.PLUGIN_ID, NLS.bind( Messages.GDB_Version_Mismatch, new Object[] { version, service.getClass().getName(), minVersion }))); } return; } } assert false; } }