/*******************************************************************************
* Copyright (c) 2000, 2008 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:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.mi.core.cdi;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.debug.core.cdi.CDIException;
import org.eclipse.cdt.debug.core.cdi.model.ICDIBreakpoint;
import org.eclipse.cdt.debug.core.cdi.model.ICDISharedLibrary;
import org.eclipse.cdt.debug.core.cdi.model.ICDITargetConfiguration;
import org.eclipse.cdt.debug.mi.core.IMIConstants;
import org.eclipse.cdt.debug.mi.core.MIException;
import org.eclipse.cdt.debug.mi.core.MIFormat;
import org.eclipse.cdt.debug.mi.core.MIPlugin;
import org.eclipse.cdt.debug.mi.core.MISession;
import org.eclipse.cdt.debug.mi.core.RxThread;
import org.eclipse.cdt.debug.mi.core.cdi.model.Breakpoint;
import org.eclipse.cdt.debug.mi.core.cdi.model.EventBreakpoint;
import org.eclipse.cdt.debug.mi.core.cdi.model.LocationBreakpoint;
import org.eclipse.cdt.debug.mi.core.cdi.model.SharedLibrary;
import org.eclipse.cdt.debug.mi.core.cdi.model.Target;
import org.eclipse.cdt.debug.mi.core.cdi.model.Watchpoint;
import org.eclipse.cdt.debug.mi.core.command.CLIInfoSharedLibrary;
import org.eclipse.cdt.debug.mi.core.command.CLISharedLibrary;
import org.eclipse.cdt.debug.mi.core.command.CommandFactory;
import org.eclipse.cdt.debug.mi.core.command.MIGDBSetAutoSolib;
import org.eclipse.cdt.debug.mi.core.command.MIGDBSetSolibSearchPath;
import org.eclipse.cdt.debug.mi.core.command.MIGDBSetStopOnSolibEvents;
import org.eclipse.cdt.debug.mi.core.command.MIGDBShow;
import org.eclipse.cdt.debug.mi.core.command.MIGDBShowSolibSearchPath;
import org.eclipse.cdt.debug.mi.core.command.MIInfoSharedLibrary;
import org.eclipse.cdt.debug.mi.core.event.MIBreakpointCreatedEvent;
import org.eclipse.cdt.debug.mi.core.event.MIEvent;
import org.eclipse.cdt.debug.mi.core.event.MISharedLibChangedEvent;
import org.eclipse.cdt.debug.mi.core.event.MISharedLibCreatedEvent;
import org.eclipse.cdt.debug.mi.core.event.MISharedLibUnloadedEvent;
import org.eclipse.cdt.debug.mi.core.output.CLIInfoSharedLibraryInfo;
import org.eclipse.cdt.debug.mi.core.output.MIBreakpoint;
import org.eclipse.cdt.debug.mi.core.output.MIGDBShowInfo;
import org.eclipse.cdt.debug.mi.core.output.MIGDBShowSolibSearchPathInfo;
import org.eclipse.cdt.debug.mi.core.output.MIInfo;
import org.eclipse.cdt.debug.mi.core.output.MIInfoSharedLibraryInfo;
import org.eclipse.cdt.debug.mi.core.output.MIShared;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/**
* Manager of the CDI shared libraries.
*/
public class SharedLibraryManager extends Manager {
ICDISharedLibrary[] EMPTY_SHAREDLIB = {};
Map sharedMap;
Set autoLoadSet;
boolean isDeferred = true;
public SharedLibraryManager (Session session) {
super(session, true);
sharedMap = new Hashtable();
autoLoadSet = new HashSet();
setAutoUpdate( MIPlugin.getDefault().getPluginPreferences().getBoolean( IMIConstants.PREF_SHARED_LIBRARIES_AUTO_REFRESH ) );
}
synchronized List getSharedList(Target target) {
List sharedList = (List)sharedMap.get(target);
if (sharedList == null) {
sharedList = Collections.synchronizedList(new ArrayList());
sharedMap.put(target, sharedList);
}
return sharedList;
}
MIShared[] getMIShareds(MISession miSession) throws CDIException {
MIShared[] miLibs = new MIShared[0];
CommandFactory factory = miSession.getCommandFactory();
MIInfoSharedLibrary infoSharedMI = factory.createMIInfoSharedLibrary();
if (infoSharedMI != null)
{
try {
RxThread rxThread = miSession.getRxThread();
rxThread.setEnableConsole(false);
miSession.postCommand(infoSharedMI);
MIInfoSharedLibraryInfo info = infoSharedMI.getMIInfoSharedLibraryInfo();
if (info == null) {
throw new CDIException(CdiResources.getString("cdi.Common.No_answer")); //$NON-NLS-1$
}
miLibs = info.getMIShared();
} catch (MIException e) {
throw new MI2CDIException(e);
}
}
else
{
CLIInfoSharedLibrary infoShared = factory.createCLIInfoSharedLibrary();
try {
RxThread rxThread = miSession.getRxThread();
rxThread.setEnableConsole(false);
miSession.postCommand(infoShared);
CLIInfoSharedLibraryInfo info = infoShared.getMIInfoSharedLibraryInfo();
if (info == null) {
throw new CDIException(CdiResources.getString("cdi.Common.No_answer")); //$NON-NLS-1$
}
miLibs = info.getMIShared();
} catch (MIException e) {
throw new MI2CDIException(e);
} finally {
RxThread rxThread = miSession.getRxThread();
rxThread.setEnableConsole(true);
}
}
return miLibs;
}
public void update(Target target) throws CDIException {
MISession miSession = target.getMISession();
Session session = (Session)target.getSession();
List eventList = updateState(target);
// A new Libraries loaded or something change, try to set the breakpoints.
if (eventList.size() > 0) {
BreakpointManager bpMgr = session.getBreakpointManager();
ICDIBreakpoint bpoints[] = null;
try {
bpoints = bpMgr.getDeferredBreakpoints(target);
} catch (CDIException e) {
bpoints = new ICDIBreakpoint[0];
}
for (int i = 0; i < bpoints.length; i++) {
if (bpoints[i] instanceof Breakpoint) {
Breakpoint bkpt = (Breakpoint)bpoints[i];
try {
boolean enable = bkpt.isEnabled();
if (bkpt instanceof LocationBreakpoint) {
bpMgr.setLocationBreakpoint((LocationBreakpoint)bkpt);
} else if (bkpt instanceof Watchpoint) {
bpMgr.setWatchpoint((Watchpoint)bkpt);
} else if (bkpt instanceof EventBreakpoint) {
bpMgr.setEventBreakpoint((EventBreakpoint)bkpt);
} else {
throw new CDIException();
}
bpMgr.deleteFromDeferredList(bkpt);
bpMgr.addToBreakpointList(bkpt);
// If the breakpoint was disable in the IDE
// install it but keep it disable
if (!enable) {
bpMgr.disableBreakpoint(bkpt);
}
MIBreakpoint[] miBreakpoints = bkpt.getMIBreakpoints();
if (miBreakpoints != null && miBreakpoints.length > 0) {
eventList.add(new MIBreakpointCreatedEvent(miSession, miBreakpoints[0].getNumber()));
}
} catch (CDIException e) {
// ignore
}
}
}
}
MIEvent[] events = (MIEvent[])eventList.toArray(new MIEvent[0]);
miSession.fireEvents(events);
}
private List updateState(Target target) throws CDIException {
MISession miSession = target.getMISession();
ICDITargetConfiguration conf = target.getConfiguration();
if (!conf.supportsSharedLibrary()) {
return Collections.EMPTY_LIST; // Bail out early;
}
MIShared[] miLibs = getMIShareds(miSession);
ArrayList newLibList = new ArrayList();
ArrayList eventList = new ArrayList(miLibs.length);
for (int i = 0; i < miLibs.length; i++) {
SharedLibrary sharedlib = getSharedLibrary(target, miLibs[i].getName());
if (sharedlib != null) {
if (hasSharedLibChanged(sharedlib, miLibs[i])) {
// Fire ChangedEvent
sharedlib.setMIShared(miLibs[i]);
eventList.add(new MISharedLibChangedEvent(miSession, miLibs[i].getName()));
}
} else {
// add the new breakpoint and fire CreatedEvent
List sharedList = getSharedList(target);
SharedLibrary lib = new SharedLibrary(target, miLibs[i]);
sharedList.add(lib);
newLibList.add(lib);
eventList.add(new MISharedLibCreatedEvent(miSession, miLibs[i].getName()));
}
}
// Check if any libraries was unloaded.
List sharedList = (List)sharedMap.get(target);
if (sharedList != null) {
SharedLibrary[] oldlibs = (SharedLibrary[]) sharedList.toArray(new SharedLibrary[sharedList.size()]);
for (int i = 0; i < oldlibs.length; i++) {
boolean found = false;
for (int j = 0; j < miLibs.length; j++) {
if (miLibs[j].getName().equals(oldlibs[i].getFileName())) {
found = true;
break;
}
}
if (!found) {
// Fire destroyed Events.
eventList.add(new MISharedLibUnloadedEvent(miSession, oldlibs[i].getFileName()));
}
}
}
eventList.addAll(autoLoadSymbols(target, (SharedLibrary[])newLibList.toArray(new SharedLibrary[newLibList.size()])));
return eventList;
}
public boolean hasSharedLibChanged(SharedLibrary lib, MIShared miLib) {
return !miLib.getName().equals(lib.getFileName()) ||
!MIFormat.getBigInteger(miLib.getFrom()).equals(lib.getStartAddress()) ||
!MIFormat.getBigInteger(miLib.getTo()).equals(lib.getEndAddress()) ||
miLib.isRead() != lib.areSymbolsLoaded();
}
/*
* this for the events
*/
public void deleteSharedLibrary(MISession miSession, SharedLibrary lib) {
Target target = ((Session)getSession()).getTarget(miSession);
List sharedList = (List)sharedMap.get(target);
if (sharedList != null) {
sharedList.remove(lib);
}
}
public SharedLibrary getSharedLibrary(MISession miSession, String name) {
Target target = ((Session)getSession()).getTarget(miSession);
return getSharedLibrary(target, name);
}
public SharedLibrary getSharedLibrary(Target target, String name) {
List sharedList = (List)sharedMap.get(target);
if (sharedList != null) {
SharedLibrary[] libs = (SharedLibrary[]) sharedList.toArray(new SharedLibrary[sharedList.size()]);
for (int i = 0; i < libs.length; i++) {
if (name.equals(libs[i].getFileName())) {
return libs[i];
}
}
}
return null;
}
public void setDeferredBreakpoint(Target target, boolean set) {
target.deferBreakpoints( set );
}
public boolean isDeferredBreakpoint(Target target) {
return target.areBreakpointsDeferred();
}
public void setAutoLoadSymbols(Target target, boolean set) throws CDIException {
MISession mi = target.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIGDBSetAutoSolib solib = factory.createMIGDBSetAutoSolib(set);
try {
mi.postCommand(solib);
solib.getMIInfo();
} catch (MIException e) {
throw new MI2CDIException(e);
}
}
public boolean isAutoLoadSymbols(Target target) throws CDIException {
MISession mi = target.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIGDBShow show = factory.createMIGDBShow(new String[]{"auto-solib-add"}); //$NON-NLS-1$
try {
mi.postCommand(show);
MIGDBShowInfo info = show.getMIGDBShowInfo();
String value = info.getValue();
if (value != null) {
return value.equalsIgnoreCase("on"); //$NON-NLS-1$
}
} catch (MIException e) {
throw new MI2CDIException(e);
}
return false;
}
public void setStopOnSolibEvents(Target target, boolean set) throws CDIException {
MISession mi = target.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIGDBSetStopOnSolibEvents stop = factory.createMIGDBSetStopOnSolibEvents(set);
try {
mi.postCommand(stop);
stop.getMIInfo();
} catch (MIException e) {
throw new MI2CDIException(e);
}
}
public boolean isStopOnSolibEvents(Target target) throws CDIException {
MISession mi = target.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIGDBShow show = factory.createMIGDBShow(new String[]{"stop-on-solib-events"}); //$NON-NLS-1$
try {
mi.postCommand(show);
MIGDBShowInfo info = show.getMIGDBShowInfo();
String value = info.getValue();
if (value != null) {
return value.equalsIgnoreCase("1"); //$NON-NLS-1$
}
} catch (MIException e) {
throw new MI2CDIException(e);
}
return false;
}
public void setSharedLibraryPaths(Target target, String[] libPaths) throws CDIException {
MISession mi = target.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIGDBSetSolibSearchPath solib = factory.createMIGDBSetSolibSearchPath(libPaths);
try {
mi.postCommand(solib);
solib.getMIInfo();
} catch (MIException e) {
throw new MI2CDIException(e);
}
}
public String[] getSharedLibraryPaths(Target target) throws CDIException {
MISession mi = target.getMISession();
CommandFactory factory = mi.getCommandFactory();
MIGDBShowSolibSearchPath dir = factory.createMIGDBShowSolibSearchPath();
try {
mi.postCommand(dir);
MIGDBShowSolibSearchPathInfo info = dir.getMIGDBShowSolibSearchPathInfo();
return info.getDirectories();
} catch (MIException e) {
throw new MI2CDIException(e);
}
}
public ICDISharedLibrary[] getSharedLibraries(Target target) throws CDIException {
List sharedList = (List)sharedMap.get(target);
if (sharedList != null) {
return (ICDISharedLibrary[]) sharedList.toArray(new ICDISharedLibrary[sharedList.size()]);
}
return EMPTY_SHAREDLIB;
}
public void loadSymbols(Target target) throws CDIException {
MISession mi = target.getMISession();
CommandFactory factory = mi.getCommandFactory();
CLISharedLibrary sharedlibrary = factory.createCLISharedLibrary();
try {
mi.postCommand(sharedlibrary);
MIInfo info = sharedlibrary.getMIInfo();
if (info == null) {
throw new CDIException(CdiResources.getString("cdi.Common.No_answer")); //$NON-NLS-1$
}
} catch (MIException e) {
throw new MI2CDIException(e);
}
update(target);
}
public void loadSymbols(Target target, ICDISharedLibrary[] libs) throws CDIException {
MISession miSession = target.getMISession();
CommandFactory factory = miSession.getCommandFactory();
for (int i = 0; i < libs.length; i++) {
if (libs[i].areSymbolsLoaded()) {
continue;
}
CLISharedLibrary sharedlibrary = factory.createCLISharedLibrary(libs[i].getFileName());
try {
miSession.postCommand(sharedlibrary);
MIInfo info = sharedlibrary.getMIInfo();
if (info == null) {
throw new CDIException(CdiResources.getString("cdi.Common.No_answer")); //$NON-NLS-1$
}
} catch (MIException e) {
throw new MI2CDIException(e);
}
// Do not do this, error are not propagate by the CLI "shared command
// So we have to manually recheck all the shared with "info shared"
//((SharedLibrary)libs[i]).getMIShared().setSymbolsRead(true);
//mi.fireEvent(new MISharedLibChangedEvent(libs[i].getFileName()));
update(target);
}
}
public boolean supportsAutoLoadSymbols() {
return true;
}
public boolean supportsStopOnSolibEvents() {
return true;
}
public void autoLoadSymbols( File[] libs ) {
autoLoadSet.addAll( Arrays.asList( libs ) );
}
private List autoLoadSymbols(Target target, SharedLibrary[] libs) throws CDIException {
ArrayList eventList = new ArrayList(libs.length);
MISession miSession = target.getMISession();
CommandFactory factory = miSession.getCommandFactory();
for (int i = 0; i < libs.length; i++) {
IPath path = new Path( libs[i].getFileName() );
File file = new File( path.lastSegment() );
if (libs[i].areSymbolsLoaded() || !autoLoadSet.contains(file)) {
continue;
}
CLISharedLibrary sharedlibrary = factory.createCLISharedLibrary(libs[i].getFileName());
try {
miSession.postCommand(sharedlibrary);
MIInfo info = sharedlibrary.getMIInfo();
if (info == null) {
throw new CDIException(CdiResources.getString("cdi.Common.No_answer")); //$NON-NLS-1$
}
} catch (MIException e) {
throw new MI2CDIException(e);
}
libs[i].getMIShared().setSymbolsRead( true );
eventList.add(new MISharedLibChangedEvent(miSession, libs[i].getFileName()));
}
return eventList;
}
}