blob: 402f340b09e3f62c8f5d835f3c11d5f8d75806d1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2015 Wind River Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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"), //$NON-NLS-1$
new ModuleDMContext(this, DMContexts.EMPTY_CONTEXTS_ARRAY, "example module 2") }); //$NON-NLS-1$
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();
}
}