| /******************************************************************************* |
| * Copyright (c) 2007 - 2010 QNX Software Systems 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: |
| * Doug Schaefer, Adrian Petrescu - QNX Software Systems - Initial API and implementation |
| * Andy Jin - Hardware debugging UI improvements, bug 229946 |
| * Peter Vidler - Monitor support (progress and cancellation) bug 242699 |
| * Bruce Griffith, Sage Electronic Engineering, LLC - bug 305943 |
| * - API generalization to become transport-independent (allow |
| * connections via serial ports and pipes). |
| *******************************************************************************/ |
| |
| package org.eclipse.cdt.debug.gdbjtag.core; |
| |
| import java.io.File; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.cdt.core.IBinaryParser.IBinaryObject; |
| import org.eclipse.cdt.debug.core.CDebugCorePlugin; |
| import org.eclipse.cdt.debug.core.CDebugUtils; |
| import org.eclipse.cdt.debug.core.ICDTLaunchConfigurationConstants; |
| import org.eclipse.cdt.debug.core.cdi.ICDISession; |
| import org.eclipse.cdt.debug.core.cdi.model.ICDITarget; |
| import org.eclipse.cdt.debug.gdbjtag.core.jtagdevice.GDBJtagDeviceContribution; |
| import org.eclipse.cdt.debug.gdbjtag.core.jtagdevice.GDBJtagDeviceContributionFactory; |
| import org.eclipse.cdt.debug.gdbjtag.core.jtagdevice.IGDBJtagDevice; |
| import org.eclipse.cdt.debug.mi.core.AbstractGDBCDIDebugger; |
| import org.eclipse.cdt.debug.mi.core.MIException; |
| import org.eclipse.cdt.debug.mi.core.MIPlugin; |
| import org.eclipse.cdt.debug.mi.core.MISession; |
| import org.eclipse.cdt.debug.mi.core.cdi.Session; |
| import org.eclipse.cdt.debug.mi.core.cdi.model.Target; |
| import org.eclipse.cdt.debug.mi.core.command.CLICommand; |
| import org.eclipse.cdt.debug.mi.core.command.MICommand; |
| import org.eclipse.cdt.debug.mi.core.command.Command; |
| import org.eclipse.cdt.debug.mi.core.command.CommandFactory; |
| import org.eclipse.cdt.debug.mi.core.command.MIGDBSetNewConsole; |
| import org.eclipse.cdt.debug.mi.core.output.MIInfo; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.core.variables.VariablesPlugin; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.ILaunchConfiguration; |
| |
| /** |
| * Debugger class for Jtag debugging (using gdb server) |
| */ |
| public class GDBJtagDebugger extends AbstractGDBCDIDebugger { |
| |
| private String miVersion; |
| |
| @Override |
| public ICDISession createSession(ILaunch launch, File executable, |
| IProgressMonitor monitor) throws CoreException { |
| return super.createSession(launch, executable, monitor); |
| } |
| |
| @Override |
| public ICDISession createDebuggerSession(ILaunch launch, IBinaryObject exe, |
| IProgressMonitor monitor) throws CoreException { |
| return super.createDebuggerSession(launch, exe, monitor); |
| } |
| |
| @Override |
| protected CommandFactory getCommandFactory(ILaunchConfiguration config) |
| throws CoreException { |
| miVersion = MIPlugin.getMIVersion(config); |
| return new GDBJtagCommandFactory(miVersion); |
| } |
| |
| @Override |
| @SuppressWarnings("deprecation") |
| protected void doStartSession(ILaunch launch, Session session, IProgressMonitor monitor) throws CoreException { |
| SubMonitor submonitor = SubMonitor.convert(monitor, 100); |
| |
| try { |
| submonitor.subTask(Messages.getString("GDBJtagDebugger.0")); //$NON-NLS-1$ |
| ILaunchConfiguration config = launch.getLaunchConfiguration(); |
| ICDITarget[] targets = session.getTargets(); |
| if (targets.length == 0 || !(targets[0] instanceof Target)) { |
| Activator.log(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), |
| DebugPlugin.INTERNAL_ERROR, Messages.getString("GDBJtagDebugger.1"), null)); //$NON-NLS-1$ |
| return; |
| } |
| MISession miSession = ((Target)targets[0]).getMISession(); |
| CommandFactory factory = miSession.getCommandFactory(); |
| if (submonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| try { |
| MIGDBSetNewConsole newConsole = factory.createMIGDBSetNewConsole(); |
| miSession.postCommand(newConsole); |
| MIInfo info = newConsole.getMIInfo(); |
| if (info == null) { |
| throw new MIException(MIPlugin.getResourceString("src.common.No_answer")); //$NON-NLS-1$ |
| } |
| } |
| catch( MIException e ) { |
| // We ignore this exception, for example |
| // on GNU/Linux the new-console is an error. |
| } |
| |
| submonitor.worked(10); |
| if (submonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| IGDBJtagDevice gdbJtagDevice; |
| try { |
| gdbJtagDevice = getGDBJtagDevice(config); |
| } catch (NullPointerException e) { |
| return; |
| } |
| |
| List<String> commands = new ArrayList<String>(); |
| |
| if (submonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| // execute symbol load |
| boolean doLoadSymbols = config.getAttribute(IGDBJtagConstants.ATTR_LOAD_SYMBOLS, IGDBJtagConstants.DEFAULT_LOAD_SYMBOLS); |
| if (doLoadSymbols) { |
| String symbolsFileName = null; |
| // New setting in Helios. Default is true. Check for existence |
| // in order to support older launch configs |
| if (config.hasAttribute(IGDBJtagConstants.ATTR_USE_PROJ_BINARY_FOR_SYMBOLS) && |
| config.getAttribute(IGDBJtagConstants.ATTR_USE_PROJ_BINARY_FOR_SYMBOLS, IGDBJtagConstants.DEFAULT_USE_PROJ_BINARY_FOR_SYMBOLS)) { |
| IPath programFile = CDebugUtils.verifyProgramPath(config); |
| if (programFile != null) { |
| symbolsFileName = programFile.toOSString(); |
| } |
| } |
| else { |
| symbolsFileName = config.getAttribute(IGDBJtagConstants.ATTR_SYMBOLS_FILE_NAME, IGDBJtagConstants.DEFAULT_SYMBOLS_FILE_NAME); |
| if (symbolsFileName.length() > 0) { |
| symbolsFileName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(symbolsFileName); |
| } |
| } |
| if (symbolsFileName == null) { |
| // The launch config GUI should prevent this from happening, but just in case |
| throw new CoreException(new Status( IStatus.ERROR, |
| Activator.getUniqueIdentifier(), |
| -1, Messages.getString("GDBJtagDebugger.err_no_sym_file"), null)); |
| } |
| |
| // Escape windows path separator characters TWICE, once for Java and once for GDB. |
| symbolsFileName = symbolsFileName.replace("\\", "\\\\"); |
| |
| String symbolsOffset = config.getAttribute(IGDBJtagConstants.ATTR_SYMBOLS_OFFSET, IGDBJtagConstants.DEFAULT_SYMBOLS_OFFSET); |
| if (symbolsOffset.length() > 0) { |
| symbolsOffset = "0x" + symbolsOffset; |
| } |
| commands.clear(); |
| gdbJtagDevice.doLoadSymbol(symbolsFileName, symbolsOffset, commands); |
| monitor.beginTask(Messages.getString("GDBJtagDebugger.loading_symbols"), 1); //$NON-NLS-1$ |
| executeGDBScript(getGDBScript(commands), miSession, submonitor.newChild(15)); |
| } |
| |
| if (submonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| |
| // hook up to remote target |
| boolean useRemote = config.getAttribute(IGDBJtagConstants.ATTR_USE_REMOTE_TARGET, IGDBJtagConstants.DEFAULT_USE_REMOTE_TARGET); |
| if (useRemote) { |
| submonitor.subTask(Messages.getString("GDBJtagDebugger.2")); //$NON-NLS-1$ |
| try { |
| commands.clear(); |
| if (gdbJtagDevice instanceof IGDBJtagConnection) { |
| URI connection = new URI(config.getAttribute(IGDBJtagConstants.ATTR_CONNECTION, IGDBJtagConstants.DEFAULT_CONNECTION)); |
| IGDBJtagConnection device = (IGDBJtagConnection)gdbJtagDevice; |
| device.doRemote(connection.getSchemeSpecificPart(), commands); |
| } else { |
| // use deprecated methods tied to TCP/IP |
| String ipAddress = config.getAttribute(IGDBJtagConstants.ATTR_IP_ADDRESS, ""); //$NON-NLS-1$ |
| int portNumber = config.getAttribute(IGDBJtagConstants.ATTR_PORT_NUMBER, 0); |
| gdbJtagDevice.doRemote(ipAddress, portNumber, commands); |
| } |
| } catch (URISyntaxException e) { |
| throw new OperationCanceledException(); |
| } |
| executeGDBScript(getGDBScript(commands), miSession, submonitor.newChild(10)); |
| if (submonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| } |
| |
| // execute init script |
| submonitor.subTask(Messages.getString("GDBJtagDebugger.3")); //$NON-NLS-1$ |
| submonitor.setWorkRemaining(80); // compensate for optional work above |
| |
| // Run device-specific code to reset the board |
| if (config.getAttribute(IGDBJtagConstants.ATTR_DO_RESET, IGDBJtagConstants.DEFAULT_DO_RESET)) { |
| commands.clear(); |
| gdbJtagDevice.doReset(commands); |
| int defaultDelay = gdbJtagDevice.getDefaultDelay(); |
| gdbJtagDevice.doDelay(config.getAttribute(IGDBJtagConstants.ATTR_DELAY, defaultDelay), commands); |
| executeGDBScript(getGDBScript(commands), miSession, submonitor.newChild(15)); |
| } |
| submonitor.setWorkRemaining(65); // compensate for optional work above |
| |
| // Run device-specific code to halt the board |
| if (config.getAttribute(IGDBJtagConstants.ATTR_DO_HALT, IGDBJtagConstants.DEFAULT_DO_HALT)) { |
| commands.clear(); |
| gdbJtagDevice.doHalt(commands); |
| executeGDBScript(getGDBScript(commands), miSession, submonitor.newChild(15)); |
| } |
| submonitor.setWorkRemaining(50); // compensate for optional work above |
| // execute any user defined init command |
| executeGDBScript(config, IGDBJtagConstants.ATTR_INIT_COMMANDS, miSession, |
| submonitor.newChild(15)); |
| |
| // execute load |
| boolean doLoad = config.getAttribute(IGDBJtagConstants.ATTR_LOAD_IMAGE, IGDBJtagConstants.DEFAULT_LOAD_IMAGE); |
| if (doLoad) { |
| String imageFileName = null; |
| |
| // New setting in Helios. Default is true. Check for existence |
| // in order to support older launch configs |
| if (config.hasAttribute(IGDBJtagConstants.ATTR_USE_PROJ_BINARY_FOR_IMAGE) && |
| config.getAttribute(IGDBJtagConstants.ATTR_USE_PROJ_BINARY_FOR_IMAGE, IGDBJtagConstants.DEFAULT_USE_PROJ_BINARY_FOR_IMAGE)) { |
| IPath programFile = CDebugUtils.verifyProgramPath(config); |
| if (programFile != null) { |
| imageFileName = programFile.toOSString(); |
| } |
| } |
| else { |
| imageFileName = config.getAttribute(IGDBJtagConstants.ATTR_IMAGE_FILE_NAME, IGDBJtagConstants.DEFAULT_IMAGE_FILE_NAME); |
| if (imageFileName.length() > 0) { |
| imageFileName = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(imageFileName); |
| } |
| } |
| if (imageFileName == null) { |
| // The launch config GUI should prevent this from happening, but just in case |
| throw new CoreException(new Status( IStatus.ERROR, |
| Activator.getUniqueIdentifier(), |
| -1, Messages.getString("GDBJtagDebugger.err_no_img_file"), null)); |
| } |
| imageFileName = imageFileName.replace("\\", "\\\\"); |
| |
| String imageOffset = config.getAttribute(IGDBJtagConstants.ATTR_IMAGE_OFFSET, IGDBJtagConstants.DEFAULT_IMAGE_OFFSET); |
| if (imageOffset.length() > 0) { |
| imageOffset = (imageFileName.endsWith(".elf")) ? "" : "0x" + config.getAttribute(IGDBJtagConstants.ATTR_IMAGE_OFFSET, IGDBJtagConstants.DEFAULT_IMAGE_OFFSET); |
| } |
| |
| commands.clear(); |
| gdbJtagDevice.doLoadImage(imageFileName, imageOffset, commands); |
| monitor.beginTask(Messages.getString("GDBJtagDebugger.loading_image"), 1); //$NON-NLS-1$ |
| executeGDBScript(getGDBScript(commands), miSession, submonitor.newChild(20)); |
| |
| |
| } |
| submonitor.setWorkRemaining(15); // compensate for optional work above |
| } catch (OperationCanceledException e) { |
| if (launch != null && launch.canTerminate()) { |
| launch.terminate(); |
| } |
| } |
| } |
| |
| public void doRunSession(ILaunch launch, ICDISession session, IProgressMonitor monitor) throws CoreException { |
| SubMonitor submonitor = SubMonitor.convert(monitor, 100); |
| |
| try { |
| ILaunchConfiguration config = launch.getLaunchConfiguration(); |
| ICDITarget[] targets = session.getTargets(); |
| if ( targets.length == 0 || !(targets[0] instanceof Target) ) |
| return; |
| MISession miSession = ((Target)targets[0]).getMISession(); |
| |
| IGDBJtagDevice gdbJtagDevice; |
| try { |
| gdbJtagDevice = getGDBJtagDevice(config); |
| } catch (NullPointerException e) { |
| return; |
| } |
| |
| if (submonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| submonitor.worked(20); |
| List<String> commands = new ArrayList<String>(); |
| // Set program counter |
| boolean setPc = config.getAttribute(IGDBJtagConstants.ATTR_SET_PC_REGISTER, IGDBJtagConstants.DEFAULT_SET_PC_REGISTER); |
| if (setPc) { |
| String pcRegister = config.getAttribute(IGDBJtagConstants.ATTR_PC_REGISTER, config.getAttribute(IGDBJtagConstants.ATTR_IMAGE_OFFSET, IGDBJtagConstants.DEFAULT_PC_REGISTER)); |
| gdbJtagDevice.doSetPC(pcRegister, commands); |
| executeGDBScript(getGDBScript(commands), miSession, submonitor.newChild(20)); |
| } |
| submonitor.setWorkRemaining(60); // compensate for optional work above |
| |
| // execute run script |
| monitor.beginTask(Messages.getString("GDBJtagDebugger.18"), 1); //$NON-NLS-1$ |
| boolean setStopAt = config.getAttribute(IGDBJtagConstants.ATTR_SET_STOP_AT, IGDBJtagConstants.DEFAULT_SET_STOP_AT); |
| if (setStopAt) { |
| String stopAt = config.getAttribute(IGDBJtagConstants.ATTR_STOP_AT, IGDBJtagConstants.DEFAULT_STOP_AT); |
| commands.clear(); |
| gdbJtagDevice.doStopAt(stopAt, commands); |
| executeGDBScript(getGDBScript(commands), miSession, submonitor.newChild(20)); |
| } |
| submonitor.setWorkRemaining(40); // compensate for optional work above |
| |
| boolean setResume = config.getAttribute(IGDBJtagConstants.ATTR_SET_RESUME, IGDBJtagConstants.DEFAULT_SET_RESUME); |
| if (setResume) { |
| commands.clear(); |
| gdbJtagDevice.doContinue(commands); |
| executeGDBScript(getGDBScript(commands), miSession, submonitor.newChild(20)); |
| } |
| submonitor.setWorkRemaining(20); // compensate for optional work above |
| // Run any user defined command |
| executeGDBScript(config, IGDBJtagConstants.ATTR_RUN_COMMANDS, miSession, |
| submonitor.newChild(20)); |
| } catch (OperationCanceledException e) { |
| if (launch != null && launch.canTerminate()) { |
| launch.terminate(); |
| } |
| } |
| } |
| |
| private void executeGDBScript(String script, MISession miSession, |
| IProgressMonitor monitor) throws CoreException { |
| // Try to execute any extra command |
| if (script == null || script.length() == 0) |
| return; |
| script = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(script); |
| String[] commands = script.split("\\r?\\n"); |
| SubMonitor submonitor = SubMonitor.convert(monitor, commands.length); |
| for (int j = 0; j < commands.length; ++j) { |
| try { |
| submonitor.subTask(Messages.getString("GDBJtagDebugger.21") + commands[j]); //$NON-NLS-1$ |
| Command cmd = null; |
| if (commands[j].startsWith("-")) { |
| cmd = new MICommand(miVersion, commands[j]); |
| } else { |
| cmd = new CLICommand(commands[j]); |
| } |
| miSession.postCommand(cmd, MISession.FOREVER); |
| submonitor.worked(1); |
| if (submonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| MIInfo info = cmd.getMIInfo(); |
| if (info == null) { |
| throw new MIException("Timeout"); //$NON-NLS-1$ |
| } |
| } catch (MIException e) { |
| MultiStatus status = new MultiStatus( |
| Activator.PLUGIN_ID, |
| ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR, |
| Messages.getString("GDBJtagDebugger.22"), e); //$NON-NLS-1$ |
| status |
| .add(new Status( |
| IStatus.ERROR, |
| Activator.PLUGIN_ID, |
| ICDTLaunchConfigurationConstants.ERR_INTERNAL_ERROR, |
| e == null ? "" : e.getLocalizedMessage(), //$NON-NLS-1$ |
| e)); |
| CDebugCorePlugin.log(status); |
| } |
| } |
| } |
| |
| private void executeGDBScript(ILaunchConfiguration configuration, String attribute, |
| MISession miSession, IProgressMonitor monitor) throws CoreException { |
| executeGDBScript(configuration.getAttribute(attribute, ""), miSession, monitor); //$NON-NLS-1$ |
| } |
| |
| private IGDBJtagDevice getGDBJtagDevice (ILaunchConfiguration config) |
| throws CoreException, NullPointerException { |
| IGDBJtagDevice gdbJtagDevice = null; |
| String jtagDeviceName = config.getAttribute(IGDBJtagConstants.ATTR_JTAG_DEVICE, IGDBJtagConstants.DEFAULT_JTAG_DEVICE); |
| GDBJtagDeviceContribution[] availableDevices = GDBJtagDeviceContributionFactory. |
| getInstance().getGDBJtagDeviceContribution(); |
| for (int i = 0; i < availableDevices.length; i++) { |
| if (jtagDeviceName.equals(availableDevices[i].getDeviceName())) { |
| gdbJtagDevice = availableDevices[i].getDevice(); |
| break; |
| } |
| } |
| return gdbJtagDevice; |
| } |
| |
| private String getGDBScript(List<String> commands) { |
| if (commands.isEmpty()) |
| return null; |
| StringBuffer sb = new StringBuffer(); |
| for (String cmd : commands) { |
| sb.append(cmd); |
| } |
| return sb.toString(); |
| } |
| } |