/******************************************************************************* * Copyright (c) 2007, 2015 Wind River 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: * Wind River Systems - initial API and implementation * Ericsson AB - Modules implementation for GDB *******************************************************************************/ package org.eclipse.cdt.dsf.mi.service; import java.math.BigInteger; import java.util.Hashtable; import org.eclipse.cdt.core.IAddress; import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor; import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor; import org.eclipse.cdt.dsf.concurrent.RequestMonitor; import org.eclipse.cdt.dsf.datamodel.AbstractDMContext; import org.eclipse.cdt.dsf.datamodel.AbstractDMEvent; import org.eclipse.cdt.dsf.datamodel.DMContexts; import org.eclipse.cdt.dsf.datamodel.IDMContext; import org.eclipse.cdt.dsf.debug.service.ICachingService; import org.eclipse.cdt.dsf.debug.service.IModules; import org.eclipse.cdt.dsf.debug.service.IModules2; import org.eclipse.cdt.dsf.debug.service.command.CommandCache; import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService; import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin; import org.eclipse.cdt.dsf.mi.service.command.CommandFactory; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoSharedLibraryInfo; import org.eclipse.cdt.dsf.mi.service.command.output.CLIInfoSharedLibraryInfo.DsfMISharedInfo; import org.eclipse.cdt.dsf.mi.service.command.output.MIInfo; import org.eclipse.cdt.dsf.service.AbstractDsfService; import org.eclipse.cdt.dsf.service.DsfServiceEventHandler; import org.eclipse.cdt.dsf.service.DsfSession; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.osgi.framework.BundleContext; /** * */ public class MIModules extends AbstractDsfService implements IModules2, ICachingService { private static class SymbolsLoadedEvent extends AbstractDMEvent<ISymbolDMContext> implements ISymbolsLoadedDMEvent { private IModuleDMContext[] fModules; public SymbolsLoadedEvent(ISymbolDMContext context, IModuleDMContext[] modules) { super(context); fModules = modules; } @Override public IModuleDMContext[] getModules() { return fModules; } } private CommandCache fModulesCache; private CommandCache fModulesLoadCache; private CommandFactory fCommandFactory; public MIModules(DsfSession session) { super(session); } @Override protected BundleContext getBundleContext() { return GdbPlugin.getBundleContext(); } @Override public void initialize(final RequestMonitor requestMonitor) { super.initialize( new ImmediateRequestMonitor(requestMonitor) { @Override protected void handleSuccess() { doInitialize(requestMonitor); }}); } private void doInitialize(RequestMonitor requestMonitor) { // Cache for holding Modules data ICommandControlService commandControl = getServicesTracker().getService(ICommandControlService.class); fModulesCache = new CommandCache(getSession(), commandControl); fModulesCache.setContextAvailable(commandControl.getContext(), true); fModulesLoadCache = new CommandCache(getSession(), commandControl); fModulesLoadCache.setContextAvailable(commandControl.getContext(), true); fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory(); /* * Make ourselves known so clients can use us. */ register(new String[]{ IModules.class.getName(), IModules2.class.getName(), MIModules.class.getName() }, new Hashtable<String,String>()); requestMonitor.done(); } @Override public void shutdown(RequestMonitor requestMonitor) { unregister(); super.shutdown(requestMonitor); } static class ModuleDMContext extends AbstractDMContext implements IModuleDMContext { private final String fFile; ModuleDMContext(MIModules service, IDMContext[] parents, String file) { super(service, parents); fFile = file; } public String getFile() { return fFile; } @Override public boolean equals(Object obj) { return baseEquals(obj) && fFile.equals(((ModuleDMContext)obj).fFile); } @Override public int hashCode() { return baseHashCode() + fFile.hashCode(); } @Override public String toString() { return baseToString() + ".file[" + fFile + "]"; //$NON-NLS-1$ //$NON-NLS-2$ } } static class ModuleDMData implements IModuleDMData { private final String fFile; private final String fFromAddress; private final String fToAddress; private final boolean fIsSymbolsRead; public ModuleDMData(ModuleDMContext dmc) { fFile = dmc.fFile; fFromAddress = null; fToAddress = null; fIsSymbolsRead = false; } public ModuleDMData(String fileName, String fromAddress, String toAddress, boolean isSymsRead){ fFile = fileName; fFromAddress = fromAddress; fToAddress = toAddress; fIsSymbolsRead = isSymsRead; } @Override public String getFile() { return fFile; } @Override public String getName() { return fFile; } @Override public long getTimeStamp() { return 0; } @Override public String getBaseAddress() { return fFromAddress; } @Override public String getToAddress() { return fToAddress; } @Override public boolean isSymbolsLoaded() { return fIsSymbolsRead; } @Override public long getSize() { long result = 0; if(getBaseAddress() == null || getToAddress() == null) return result; BigInteger start = MIFormat.getBigInteger(getBaseAddress()); BigInteger end = MIFormat.getBigInteger(getToAddress()); if ( end.compareTo( start ) > 0 ) result = end.subtract( start ).longValue(); return result; } } @Override public void getModules(final ISymbolDMContext symCtx, final DataRequestMonitor<IModuleDMContext[]> rm) { if(symCtx != null){ fModulesCache.execute(fCommandFactory.createCLIInfoSharedLibrary(symCtx), new DataRequestMonitor<CLIInfoSharedLibraryInfo>(getExecutor(), rm) { @Override protected void handleSuccess() { rm.setData(makeModuleContexts(symCtx, getData())); rm.done(); } }); } else{ rm.setData(new IModuleDMContext[] { new ModuleDMContext(this, DMContexts.EMPTY_CONTEXTS_ARRAY, "example module 1"), new ModuleDMContext(this, DMContexts.EMPTY_CONTEXTS_ARRAY, "example module 2") }); //$NON-NLS-1$ //$NON-NLS-2$ rm.done(); } } private IModuleDMContext[] makeModuleContexts(IDMContext symCtxt, CLIInfoSharedLibraryInfo info){ DsfMISharedInfo[] sharedInfos = info.getMIShared(); ModuleDMContext[] modules = new ModuleDMContext[sharedInfos.length]; int i = 0; for(DsfMISharedInfo shared : sharedInfos){ modules[i++] = new ModuleDMContext(this, new IDMContext[]{symCtxt}, shared.getName()); } return modules; } @Override public void getModuleData(final IModuleDMContext dmc, final DataRequestMonitor<IModuleDMData> rm) { assert dmc != null; ISymbolDMContext symDmc = DMContexts.getAncestorOfType(dmc, ISymbolDMContext.class); if (symDmc != null && dmc instanceof ModuleDMContext) { fModulesCache.execute(fCommandFactory.createCLIInfoSharedLibrary(symDmc), new DataRequestMonitor<CLIInfoSharedLibraryInfo>(getExecutor(), rm) { @Override protected void handleSuccess() { rm.setData( createSharedLibInfo((ModuleDMContext)dmc, getData()) ); rm.done(); } }); } else { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Unknown DM Context", null)); //$NON-NLS-1$ rm.done(); } } /** * @since 4.6 */ @Override public void loadSymbolsForAllModules(final ISymbolDMContext symDmc, final RequestMonitor rm) { assert symDmc != null; if (symDmc != null) { fModulesLoadCache.execute(fCommandFactory.createCLISharedLibrary(symDmc), new ImmediateDataRequestMonitor<MIInfo>(rm) { @Override protected void handleSuccess() { getModules(symDmc, new ImmediateDataRequestMonitor<IModuleDMContext[]>() { @Override protected void handleCompleted() { if (isSuccess()) { getSession().dispatchEvent(new SymbolsLoadedEvent(symDmc, getData()), getProperties()); } else { // Some error in getting the list of modules. Send an event anyway without the list getSession().dispatchEvent(new SymbolsLoadedEvent(symDmc, new IModuleDMContext[0]), getProperties()); } rm.done(); }; }); } }); } else { rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid DM Context", null)); //$NON-NLS-1$ } } /** * @since 4.6 */ @Override public void loadSymbols(final IModuleDMContext modDmc, final RequestMonitor rm) { assert modDmc != null; final ISymbolDMContext symDmc = DMContexts.getAncestorOfType(modDmc, ISymbolDMContext.class); if (symDmc != null && modDmc instanceof ModuleDMContext) { fModulesLoadCache.execute(fCommandFactory.createCLISharedLibrary(symDmc, ((ModuleDMContext)modDmc).getFile()), new ImmediateDataRequestMonitor<MIInfo>(rm) { @Override protected void handleSuccess() { getSession().dispatchEvent(new SymbolsLoadedEvent(symDmc, new IModuleDMContext[] { modDmc }), getProperties()); rm.done(); } }); } else { rm.done(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid DM Context", null)); //$NON-NLS-1$ } } private IModuleDMData createSharedLibInfo(ModuleDMContext dmc, CLIInfoSharedLibraryInfo info){ for (CLIInfoSharedLibraryInfo.DsfMISharedInfo shared : info.getMIShared()) { if(shared.getName().equals(dmc.fFile)){ return new ModuleDMData(shared.getName(), shared.getFrom(), shared.getTo(), shared.isRead()); } } return new ModuleDMData("","", "", false); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } @Override public void calcAddressInfo(ISymbolDMContext symCtx, String file, int line, int col, DataRequestMonitor<AddressRange[]> rm) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Functionality not supported", null)); //$NON-NLS-1$ rm.done(); } @Override public void calcLineInfo(ISymbolDMContext symCtx, IAddress address, DataRequestMonitor<LineInfo[]> rm) { rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, NOT_SUPPORTED, "Functionality not supported", null)); //$NON-NLS-1$ rm.done(); } /** @since 4.6 */ @DsfServiceEventHandler public void eventDispatched(ISymbolsLoadedDMEvent e) { fModulesCache.reset(); // Do not clear fModulesLoadCache since those commands do not need to be resent. } /** * {@inheritDoc} * @since 1.1 */ @Override public void flushCache(IDMContext context) { fModulesCache.reset(); fModulesLoadCache.reset(); } }