/******************************************************************************* * Copyright (c) 2007, 2016 Wind River Systems, Inc. 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 *******************************************************************************/ package org.eclipse.tcf.internal.debug.model; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IBreakpointListener; import org.eclipse.debug.core.IBreakpointManager; import org.eclipse.debug.core.IBreakpointManagerListener; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.tcf.internal.debug.Activator; import org.eclipse.tcf.protocol.IChannel; import org.eclipse.tcf.protocol.IToken; import org.eclipse.tcf.protocol.JSON; import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.services.IBreakpoints; /** * TCFBreakpointsModel class handles breakpoints for all active TCF launches. * It downloads initial set of breakpoint data when launch is activated, * listens for Eclipse breakpoint manager events and propagates breakpoint changes to TCF targets. */ public class TCFBreakpointsModel { public static final String CDATA_CLIENT_ID = "ClientID", CDATA_TYPE = "Type", CDATA_FILE = "File", CDATA_MARKER = "Marker"; public static final String ATTR_ID = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, ATTR_STATUS = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + "Status", ATTR_MESSAGE = IMarker.MESSAGE, ATTR_ENABLED = IBreakpoint.ENABLED, ATTR_INSTALL_COUNT = "org.eclipse.cdt.debug.core.installCount", ATTR_ADDRESS = "org.eclipse.cdt.debug.core.address", ATTR_FUNCTION = "org.eclipse.cdt.debug.core.function", ATTR_EXPRESSION = "org.eclipse.cdt.debug.core.expression", ATTR_READ = "org.eclipse.cdt.debug.core.read", ATTR_WRITE = "org.eclipse.cdt.debug.core.write", ATTR_SIZE = "org.eclipse.cdt.debug.core.range", ATTR_FILE = "org.eclipse.cdt.debug.core.sourceHandle", ATTR_LINE = IMarker.LINE_NUMBER, ATTR_CHAR = IMarker.CHAR_START, ATTR_REQESTED_FILE = "requestedSourceHandle", ATTR_REQESTED_LINE = "requestedLine", ATTR_REQESTED_CHAR = "requestedCharStart", ATTR_CONDITION = "org.eclipse.cdt.debug.core.condition", ATTR_PRINTF_STRING = "org.eclipse.cdt.debug.core.printf_string", ATTR_IGNORE_COUNT = "org.eclipse.cdt.debug.core.ignoreCount", ATTR_CONTEXTNAMES = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_CONTEXT_NAMES, ATTR_CONTEXTIDS = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_CONTEXT_IDS, ATTR_EXE_PATHS = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_EXECUTABLE_PATHS, ATTR_STOP_GROUP = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_STOP_GROUP, ATTR_CONTEXT_QUERY = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_CONTEXT_QUERY, ATTR_LINE_OFFSET = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_LINE_OFFSET, ATTR_SKIP_PROLOGUE = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_SKIP_PROLOGUE, ATTR_CT_INP = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_CT_INP, ATTR_CT_OUT = ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_CT_OUT, ATTR_EVENT_TYPE = "org.eclipse.cdt.debug.core.eventbreakpoint_event_id", ATTR_EVENT_ARGS = "org.eclipse.cdt.debug.core.eventbreakpoint_event_arg", ATTR_TYPE = "org.eclipse.cdt.debug.core.breakpointType", ATTR_TCF_STAMP = "org.eclipse.tcf.debug.tcfStamp"; public static final int ATTR_TYPE_TEMPORARY = 0x1, ATTR_TYPE_REGULAR = 0x0 << 1, ATTR_TYPE_HARDWARE = 0x1 << 1, ATTR_TYPE_SOFTWARE = 0x2 << 1; private final IBreakpointManager bp_manager = DebugPlugin.getDefault().getBreakpointManager(); private final HashMap<IChannel,Map<String,Object>> channels = new HashMap<IChannel,Map<String,Object>>(); private final HashMap<String,IBreakpoint> id2bp = new HashMap<String,IBreakpoint>(); private abstract class BreakpointUpdate implements Runnable { private final IBreakpoint breakpoint; private boolean removed; protected final Map<String,Object> marker_attrs; protected final boolean is_local; protected final String marker_id; private final String marker_file; private final String marker_type; IBreakpoints service; IBreakpoints.DoneCommand done; Map<String,Object> tcf_attrs; BreakpointUpdate(IBreakpoint breakpoint, boolean removed) throws CoreException, IOException { this.breakpoint = breakpoint; this.removed = removed; IMarker marker = breakpoint.getMarker(); marker_attrs = new HashMap<String,Object>(marker.getAttributes()); is_local = isLocal(marker); marker_file = getFilePath(breakpoint.getMarker().getResource()); marker_type = breakpoint.getMarker().getType(); marker_id = getBreakpointID(breakpoint); } synchronized void exec() throws InterruptedException { assert !Protocol.isDispatchThread(); if (marker_id != null) { Protocol.invokeLater(this); wait(); } } public void run() { if (disposed) return; if (removed) id2bp.remove(marker_id); else id2bp.put(marker_id, breakpoint); if (is_local) { for (final IChannel channel : channels.keySet()) { tcf_attrs = toBreakpointAttributes(channel, marker_id, marker_file, marker_type, marker_attrs); service = channel.getRemoteService(IBreakpoints.class); if (!isSupported(channel, breakpoint)) continue; done = new IBreakpoints.DoneCommand() { public void doneCommand(IToken token, Exception error) { if (error != null) channel.terminate(error); } }; update(); } } Protocol.sync(new Runnable() { public void run() { synchronized (BreakpointUpdate.this) { BreakpointUpdate.this.notify(); } } }); }; abstract void update(); } private final IBreakpointListener breakpoint_listener = new IBreakpointListener() { public void breakpointAdded(final IBreakpoint breakpoint) { try { new BreakpointUpdate(breakpoint, false) { @Override void update() { service.add(tcf_attrs, done); } }.exec(); } catch (Throwable x) { Activator.log("Unhandled exception in breakpoint listener", x); } } private Set<String> calcMarkerDeltaKeys(IMarker marker, IMarkerDelta delta) throws CoreException { Set<String> keys = new HashSet<String>(); if (delta == null) return keys; Map<String,Object> m0 = delta.getAttributes(); Map<String,Object> m1 = marker.getAttributes(); if (m0 != null) keys.addAll(m0.keySet()); if (m1 != null) keys.addAll(m1.keySet()); for (Iterator<String> i = keys.iterator(); i.hasNext();) { String key = i.next(); Object v0 = m0 != null ? m0.get(key) : null; Object v1 = m1 != null ? m1.get(key) : null; if (v0 instanceof String && ((String)v0).length() == 0) v0 = null; if (v1 instanceof String && ((String)v1).length() == 0) v1 = null; if (v0 instanceof Boolean && !((Boolean)v0).booleanValue()) v0 = null; if (v1 instanceof Boolean && !((Boolean)v1).booleanValue()) v1 = null; if ((v0 == null) != (v1 == null)) continue; if (v0 != null && !v0.equals(v1)) continue; i.remove(); } if (marker.getAttribute(ATTR_REQESTED_FILE, "").length() > 0) keys.remove(ATTR_FILE); if (marker.getAttribute(ATTR_REQESTED_LINE, -1) >= 0) keys.remove(ATTR_LINE); if (marker.getAttribute(ATTR_REQESTED_CHAR, -1) >= 0) keys.remove(ATTR_CHAR); keys.remove(ATTR_INSTALL_COUNT); keys.remove(ATTR_TCF_STAMP); keys.remove(ATTR_MESSAGE); keys.remove(ATTR_STATUS); return keys; } public void breakpointChanged(final IBreakpoint breakpoint, IMarkerDelta delta) { try { final Set<String> s = calcMarkerDeltaKeys(breakpoint.getMarker(), delta); if (s.isEmpty()) return; new BreakpointUpdate(breakpoint, false) { @Override void update() { if (s.size() == 1 && s.contains(ATTR_ENABLED)) { Boolean enabled = (Boolean)tcf_attrs.get(IBreakpoints.PROP_ENABLED); if (enabled == null || !enabled.booleanValue()) { service.disable(new String[]{ marker_id }, done); } else { service.enable(new String[]{ marker_id }, done); } } else { service.change(tcf_attrs, done); } } }.exec(); } catch (Throwable x) { Activator.log("Unhandled exception in breakpoint listener", x); } } public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) { try { new BreakpointUpdate(breakpoint, true) { @Override void update() { service.remove(new String[]{ marker_id }, done); } }.exec(); } catch (Throwable x) { Activator.log("Unhandled exception in breakpoint listener", x); } } }; private final IBreakpointManagerListener manager_listener = new IBreakpointManagerListener() { public void breakpointManagerEnablementChanged(final boolean enabled) { try { IBreakpoint[] arr = bp_manager.getBreakpoints(); if (arr == null || arr.length == 0) return; final Map<String,IBreakpoint> map = new HashMap<String,IBreakpoint>(); for (int i = 0; i < arr.length; i++) { IMarker marker = arr[i].getMarker(); Boolean b = marker.getAttribute(ATTR_ENABLED, Boolean.FALSE); if (!b.booleanValue()) continue; String id = getBreakpointID(arr[i]); if (id == null) continue; map.put(id, arr[i]); } if (map.isEmpty()) return; Runnable r = new Runnable() { public void run() { if (disposed) return; for (final IChannel channel : channels.keySet()) { IBreakpoints service = channel.getRemoteService(IBreakpoints.class); Set<String> ids = new HashSet<String>(); for (String id : map.keySet()) { IBreakpoint bp = map.get(id); if (isSupported(channel, bp)) ids.add(id); } IBreakpoints.DoneCommand done = new IBreakpoints.DoneCommand() { public void doneCommand(IToken token, Exception error) { if (error != null) channel.terminate(error); } }; if (enabled) { service.enable(ids.toArray(new String[ids.size()]), done); } else { service.disable(ids.toArray(new String[ids.size()]), done); } } Protocol.sync(new Runnable() { public void run() { synchronized (map) { map.notify(); } } }); } }; synchronized (map) { assert !Protocol.isDispatchThread(); Protocol.invokeLater(r); map.wait(); } } catch (Throwable x) { Activator.log("Unhandled exception in breakpoint listener", x); } } }; private boolean disposed; public static TCFBreakpointsModel getBreakpointsModel() { return Activator.getBreakpointsModel(); } public void dispose() { bp_manager.removeBreakpointListener(breakpoint_listener); bp_manager.removeBreakpointManagerListener(manager_listener); channels.clear(); disposed = true; } public boolean isSupported(IChannel channel, IBreakpoint bp) { // TODO: implement per-channel breakpoint filtering return true; } /** * Get TCF ID of a breakpoint. * @param bp - IBreakpoint object. * @return TCF ID of the breakpoint. * @throws CoreException */ public static String getBreakpointID(IBreakpoint bp) throws CoreException { IMarker marker = bp.getMarker(); String id = (String)marker.getAttributes().get(ATTR_ID); if (id != null) return id; id = marker.getResource().getLocationURI().toString(); return id + ':' + marker.getId(); } /** * Get IBreakpoint for given TCF breakpoint ID. * The mapping works only for breakpoints that were sent to (or received from) a debug target. * It can be used to map target responses to IBreakpoint objects. * @param id - TCF breakpoint ID. * @return IBreakpoint object associated with the ID, or null. */ public IBreakpoint getBreakpoint(String id) { assert Protocol.isDispatchThread(); return id2bp.get(id); } /** * Check breakpoint ownership. * @param properties - breakpoint properties as reported by TCF Breakpoints service. * @return true if the breakpoint is owned by local instance of Eclipse. * Return false if the properties represent a breakpoint created by some other TCF client. */ @SuppressWarnings("unchecked") public static boolean isLocal(Map<String,Object> properties) { if (properties == null) return false; Map<String,Object> client_data = (Map<String,Object>)properties.get(IBreakpoints.PROP_CLIENT_DATA); if (client_data == null) return false; String id = (String)client_data.get(TCFBreakpointsModel.CDATA_CLIENT_ID); return Activator.getClientID().equals(id); } /** * Check breakpoint marker ownership. * @param marker - breakpoint marker. * @return true if the marker is owned by local instance of Eclipse. * Return false if the marker represents a breakpoint created by some other TCF client. */ public static boolean isLocal(IMarker marker) { try { Map<String,Object> marker_attrs = marker.getAttributes(); if (marker_attrs == null) return false; return !Boolean.FALSE.equals(marker_attrs.get(IBreakpoint.PERSISTED)); } catch (CoreException e) { return false; } } /** * Download breakpoint info to a target. * This is supposed to be done once after a channel is opened. * @param channel - TCF communication channel. * @param done - client callback. * @throws IOException * @throws CoreException */ @SuppressWarnings("unchecked") public void downloadBreakpoints(final IChannel channel, final Runnable done) throws IOException, CoreException { assert !disposed; assert Protocol.isDispatchThread(); final IBreakpoints service = channel.getRemoteService(IBreakpoints.class); if (service == null) { Protocol.invokeLater(done); return; } service.getCapabilities(null, new IBreakpoints.DoneGetCapabilities() { public void doneGetCapabilities(IToken token, Exception error, Map<String,Object> capabilities) { if (channel.getState() != IChannel.STATE_OPEN) { Protocol.invokeLater(done); return; } if (channels.isEmpty()) { bp_manager.addBreakpointListener(breakpoint_listener); bp_manager.addBreakpointManagerListener(manager_listener); } channel.addChannelListener(new IChannel.IChannelListener() { public void congestionLevel(int level) { } public void onChannelClosed(Throwable error) { if (disposed) return; channels.remove(channel); if (channels.isEmpty()) { bp_manager.removeBreakpointListener(breakpoint_listener); bp_manager.removeBreakpointManagerListener(manager_listener); id2bp.clear(); } } public void onChannelOpened() { } }); channels.put(channel, capabilities); IBreakpoint[] arr = bp_manager.getBreakpoints(); if (arr != null && arr.length > 0) { List<Map<String,Object>> bps = new ArrayList<Map<String,Object>>(arr.length); for (int i = 0; i < arr.length; i++) { try { if (!isSupported(channel, arr[i])) continue; String id = getBreakpointID(arr[i]); if (id == null) continue; if (!arr[i].isPersisted()) continue; IMarker marker = arr[i].getMarker(); String file = getFilePath(marker.getResource()); bps.add(toBreakpointAttributes(channel, id, file, marker.getType(), marker.getAttributes())); id2bp.put(id, arr[i]); } catch (Exception x) { Activator.log("Cannot get breakpoint attributes", x); } } if (!bps.isEmpty()) { Map<String, Object>[] bp_arr = (Map<String,Object>[])bps.toArray(new Map[bps.size()]); service.set(bp_arr, new IBreakpoints.DoneCommand() { public void doneCommand(IToken token, Exception error) { if (error == null) done.run(); else channel.terminate(error); } }); return; } } Protocol.invokeLater(done); } }); } private String getFilePath(IResource resource) throws IOException { if (resource == ResourcesPlugin.getWorkspace().getRoot()) return null; IPath p = resource.getRawLocation(); if (p == null) return null; return p.toFile().getCanonicalPath(); } /** * Translate TCF breakpoint properties to Eclipse breakpoint marker attributes. * @param p - TCF breakpoint properties. * @return Eclipse marker attributes. */ @SuppressWarnings("unchecked") public Map<String,Object> toMarkerAttributes(Map<String,Object> p) { assert !disposed; assert Protocol.isDispatchThread(); Map<String,Object> client_data = (Map<String,Object>)p.get(IBreakpoints.PROP_CLIENT_DATA); if (client_data != null) { Map<String,Object> m = (Map<String,Object>)client_data.get(CDATA_MARKER); if (m != null) { m = new HashMap<String,Object>(m); m.put(ATTR_ID, p.get(IBreakpoints.PROP_ID)); Boolean enabled = (Boolean)p.get(IBreakpoints.PROP_ENABLED); m.put(ATTR_ENABLED, enabled == null ? Boolean.FALSE : enabled); return m; } } Map<String,Object> m = new HashMap<String,Object>(); for (Map.Entry<String,Object> e : p.entrySet()) { String key = e.getKey(); Object val = e.getValue(); if (key.equals(IBreakpoints.PROP_ENABLED)) continue; if (key.equals(IBreakpoints.PROP_FILE)) continue; if (key.equals(IBreakpoints.PROP_LINE)) continue; if (key.equals(IBreakpoints.PROP_COLUMN)) continue; if (key.equals(IBreakpoints.PROP_LOCATION)) continue; if (key.equals(IBreakpoints.PROP_ACCESS_MODE)) continue; if (key.equals(IBreakpoints.PROP_SIZE)) continue; if (key.equals(IBreakpoints.PROP_CONDITION)) continue; if (key.equals(IBreakpoints.PROP_EVENT_TYPE)) continue; if (key.equals(IBreakpoints.PROP_EVENT_ARGS)) continue; if (IBreakpoints.PROP_CONTEXT_IDS.equals(key) || IBreakpoints.PROP_CONTEXT_NAMES.equals(key) || IBreakpoints.PROP_STOP_GROUP.equals(key) || IBreakpoints.PROP_EXECUTABLE_PATHS.equals(key)) { if (val instanceof String[]) { StringBuffer bf = new StringBuffer(); for (String s : (String[])val) { if (bf.length() > 0) bf.append(','); bf.append(s); } if (bf.length() == 0) continue; val = bf.toString(); } else if (val instanceof Collection) { StringBuffer bf = new StringBuffer(); for (String s : (Collection<String>)val) { if (bf.length() > 0) bf.append(','); bf.append(s); } if (bf.length() == 0) continue; val = bf.toString(); } } if (!(val instanceof String) && !(val instanceof Boolean) && !(val instanceof Integer)) { // class of the value is not supported by Marker, convert to JSON string try { val = "JSON:" + JSON.toJSON(val); } catch (IOException x) { continue; } } m.put(ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + key, val); } Boolean enabled = (Boolean)p.get(IBreakpoints.PROP_ENABLED); m.put(ATTR_ENABLED, enabled == null ? Boolean.FALSE : enabled); String location = (String)p.get(IBreakpoints.PROP_LOCATION); if (location != null && location.length() > 0) { int access_mode = IBreakpoints.ACCESSMODE_EXECUTE; Number access_mode_num = (Number)p.get(IBreakpoints.PROP_ACCESS_MODE); if (access_mode_num != null) access_mode = access_mode_num.intValue(); if ((access_mode & IBreakpoints.ACCESSMODE_EXECUTE) != 0) { if (Character.isDigit(location.charAt(0))) { m.put(ATTR_ADDRESS, location); } else { m.put(ATTR_FUNCTION, location); } } else { m.put(ATTR_EXPRESSION, location.replaceFirst("^&\\((.+)\\)$", "$1")); m.put(ATTR_READ, (access_mode & IBreakpoints.ACCESSMODE_READ) != 0); m.put(ATTR_WRITE, (access_mode & IBreakpoints.ACCESSMODE_WRITE) != 0); } Number size_num = (Number)p.get(IBreakpoints.PROP_SIZE); if (size_num != null) m.put(ATTR_SIZE, size_num.toString()); } m.put(IBreakpoint.REGISTERED, Boolean.TRUE); m.put(IBreakpoint.PERSISTED, Boolean.TRUE); m.put(IBreakpoint.ID, ITCFConstants.ID_TCF_DEBUG_MODEL); String file = (String)p.get(IBreakpoints.PROP_FILE); if (file != null && file.length() > 0) { m.put(ATTR_FILE, file); } Number line = (Number)p.get(IBreakpoints.PROP_LINE); if (line != null) { m.put(ATTR_LINE, Integer.valueOf(line.intValue())); Number column = (Number)p.get(IBreakpoints.PROP_COLUMN); if (column != null) { m.put(IMarker.CHAR_START, new Integer(column.intValue())); m.put(IMarker.CHAR_END, new Integer(column.intValue() + 1)); } } String condition = (String)p.get(IBreakpoints.PROP_CONDITION); if (condition != null && condition.length() > 0) m.put(ATTR_CONDITION, condition); String event_type = (String)p.get(IBreakpoints.PROP_EVENT_TYPE); if (event_type != null && event_type.length() > 0) m.put(ATTR_EVENT_TYPE, event_type); String event_args = (String)p.get(IBreakpoints.PROP_EVENT_ARGS); if (event_args != null && event_args.length() > 0) m.put(ATTR_EVENT_ARGS, event_args); Number ignore_count = (Number)p.get(IBreakpoints.PROP_IGNORE_COUNT); if (ignore_count != null) m.put(ATTR_IGNORE_COUNT, ignore_count); Boolean temporary = (Boolean)p.get(IBreakpoints.PROP_TEMPORARY); if (temporary != null && temporary.booleanValue()) { Integer cdt_type = (Integer)m.get(ATTR_TYPE); cdt_type = cdt_type != null ? cdt_type : 0; cdt_type = cdt_type | ATTR_TYPE_TEMPORARY; m.put(ATTR_TYPE, cdt_type); } String type = (String)p.get(IBreakpoints.PROP_TYPE); if (type != null) { Integer cdt_type = (Integer)m.get(ATTR_TYPE); cdt_type = cdt_type != null ? cdt_type : 0; if (IBreakpoints.TYPE_HARDWARE.equals(type)) { cdt_type = cdt_type | ATTR_TYPE_HARDWARE; } else if (IBreakpoints.TYPE_SOFTWARE.equals(type)) { cdt_type = cdt_type | ATTR_TYPE_SOFTWARE; } m.put(ATTR_TYPE, cdt_type); } String msg = null; if (location != null) msg = location; else if (file != null && line != null) msg = file + ":" + line; else msg = (String)p.get(IBreakpoints.PROP_ID); m.put(ATTR_MESSAGE, "Breakpoint: " + msg); m.put(ATTR_TCF_STAMP, Boolean.TRUE.toString()); return m; } /** * Translate Eclipse breakpoint marker attributes to TCF breakpoint properties. * @param channel - TCF communication channel. * @param id - breakpoint ID. * @param file - the maker file or null. * @param type - the marker type. * @param p - the marker attributes. * @return TCF breakpoint properties. */ public Map<String,Object> toBreakpointAttributes(IChannel channel, String id, String marker_file, String marker_type, Map<String,Object> p) { assert !disposed; assert Protocol.isDispatchThread(); Map<String,Object> m = new HashMap<String,Object>(); Map<String,Object> capabilities = channels.get(channel); Map<String,Object> client_data = null; if (capabilities != null) { Object obj = capabilities.get(IBreakpoints.CAPABILITY_CLIENT_DATA); if (obj instanceof Boolean && ((Boolean)obj).booleanValue()) client_data = new HashMap<String,Object>(); } m.put(IBreakpoints.PROP_ID, id); if (client_data != null) { m.put(IBreakpoints.PROP_CLIENT_DATA, client_data); client_data.put(CDATA_CLIENT_ID, Activator.getClientID()); if (marker_type != null) client_data.put(CDATA_TYPE, marker_type); if (marker_file != null) client_data.put(CDATA_FILE, marker_file); Map<String,Object> x = new HashMap<String,Object>(p); x.remove(ATTR_INSTALL_COUNT); x.remove(ATTR_TCF_STAMP); x.remove(ATTR_STATUS); client_data.put(CDATA_MARKER, x); } for (Map.Entry<String,Object> e : p.entrySet()) { String key = e.getKey(); Object val = e.getValue(); if (key.equals(ATTR_STATUS)) continue; if (key.equals(ATTR_TCF_STAMP)) continue; if (key.startsWith(ITCFConstants.ID_TCF_DEBUG_MODEL)) { String tcf_key = key.substring(ITCFConstants.ID_TCF_DEBUG_MODEL.length() + 1); if (val instanceof String) { String str = (String)val; if (IBreakpoints.PROP_CONTEXT_IDS.equals(tcf_key)) { if (str.length() == 0) continue; val = filterContextIds(channel, str.split(",\\s*")); } else if (IBreakpoints.PROP_CONTEXT_QUERY.equals(tcf_key)) { if (str.length() == 0) continue; } else if (IBreakpoints.PROP_CONTEXT_NAMES.equals(tcf_key) || IBreakpoints.PROP_STOP_GROUP.equals(tcf_key) || IBreakpoints.PROP_EXECUTABLE_PATHS.equals(tcf_key)) { val = str.split(",\\s*"); } else if (str.startsWith("JSON:")) { try { val = JSON.parseOne(str.substring(5).getBytes("UTF-8")); } catch (Exception x) { // Not JSON, keep value as String } } } m.put(tcf_key, val); } } Boolean enabled = (Boolean)p.get(ATTR_ENABLED); if (enabled != null && enabled.booleanValue() && bp_manager.isEnabled()) { m.put(IBreakpoints.PROP_ENABLED, enabled); } String file = (String)p.get(ATTR_REQESTED_FILE); if (file == null || file.length() == 0) file = (String)p.get(ATTR_FILE); if (file == null || file.length() == 0) file = marker_file; if (file != null && file.trim().length() > 0) { String name = file; boolean file_mapping = false; if (capabilities != null) { Object obj = capabilities.get(IBreakpoints.CAPABILITY_FILE_MAPPING); if (obj instanceof Boolean) file_mapping = ((Boolean)obj).booleanValue(); } if (!file_mapping) { int i = file.lastIndexOf('/'); int j = file.lastIndexOf('\\'); if (i > j) name = file.substring(i + 1); else if (i < j) name = file.substring(j + 1); } m.put(IBreakpoints.PROP_FILE, name); Integer line = (Integer)p.get(ATTR_REQESTED_LINE); if (line == null || line < 0) line = (Integer)p.get(ATTR_LINE); if (line != null && line >= 0) { m.put(IBreakpoints.PROP_LINE, Integer.valueOf(line.intValue())); Integer column = (Integer)p.get(ATTR_REQESTED_CHAR); if (column == null || column < 0) column = (Integer)p.get(ATTR_CHAR); if (column != null && column >= 0) m.put(IBreakpoints.PROP_COLUMN, column); } } if (p.get(ATTR_EXPRESSION) != null) { String expr = (String)p.get(ATTR_EXPRESSION); if (expr != null && expr.length() != 0) { boolean writeAccess = Boolean.TRUE.equals(p.get(ATTR_WRITE)); boolean readAccess = Boolean.TRUE.equals(p.get(ATTR_READ)); int accessMode = 0; if (readAccess) accessMode |= IBreakpoints.ACCESSMODE_READ; if (writeAccess) accessMode |= IBreakpoints.ACCESSMODE_WRITE; m.put(IBreakpoints.PROP_ACCESS_MODE, Integer.valueOf(accessMode)); Object range = p.get(ATTR_SIZE); if (range != null) { int size = Integer.parseInt(range.toString()); if (size > 0) m.put(IBreakpoints.PROP_SIZE, size); } if (!Character.isDigit(expr.charAt(0))) { expr = "&(" + expr + ')'; } m.put(IBreakpoints.PROP_LOCATION, expr); if (m.get(IBreakpoints.PROP_FILE) != null && m.get(IBreakpoints.PROP_LINE) == null) { m.put(IBreakpoints.PROP_LINE, Integer.valueOf(1)); } } } else if (p.get(ATTR_FUNCTION) != null) { String expr = (String)p.get(ATTR_FUNCTION); if (expr != null && expr.length() != 0) { // Strip function parameters int paren = expr.indexOf('('); if (paren > 0) expr = expr.substring(0, paren); m.put(IBreakpoints.PROP_LOCATION, expr); } if (!m.containsKey(IBreakpoints.PROP_SKIP_PROLOGUE) && capabilities != null) { Object obj = capabilities.get(IBreakpoints.CAPABILITY_SKIP_PROLOGUE); if (obj instanceof Boolean && ((Boolean)obj).booleanValue()) { m.put(IBreakpoints.PROP_SKIP_PROLOGUE, true); } } } else if (file == null) { String address = (String)p.get(ATTR_ADDRESS); if (address != null && address.length() > 0) m.put(IBreakpoints.PROP_LOCATION, address); } String condition = (String)p.get(ATTR_CONDITION); String printf_string = (String)p.get(ATTR_PRINTF_STRING); if (printf_string != null && printf_string.length() > 0) if (condition != null && condition.length() > 0) condition = '(' + condition + ") && " + "$printf(" + printf_string + ')'; else condition = "$printf(" + printf_string + ')'; if (condition != null && condition.length() > 0) m.put(IBreakpoints.PROP_CONDITION, condition); String event_type = (String)p.get(ATTR_EVENT_TYPE); if (event_type != null && event_type.length() > 0) m.put(IBreakpoints.PROP_EVENT_TYPE, event_type); String event_args = (String)p.get(ATTR_EVENT_ARGS); if (event_args != null && event_args.length() > 0) m.put(IBreakpoints.PROP_EVENT_ARGS, event_args); Number ignore_count = (Number)p.get(ATTR_IGNORE_COUNT); if (ignore_count != null && ignore_count.intValue() > 0) m.put(IBreakpoints.PROP_IGNORE_COUNT, ignore_count); Integer cdt_type = (Integer)p.get(ATTR_TYPE); if (cdt_type != null) { if ((cdt_type.intValue() & ATTR_TYPE_TEMPORARY) != 0) { m.put(IBreakpoints.PROP_TEMPORARY, true); } if ((cdt_type.intValue() & ATTR_TYPE_HARDWARE) != 0) { m.put(IBreakpoints.PROP_TYPE, IBreakpoints.TYPE_HARDWARE); } else if ((cdt_type.intValue() & ATTR_TYPE_SOFTWARE) != 0) { m.put(IBreakpoints.PROP_TYPE, IBreakpoints.TYPE_SOFTWARE); } else { m.put(IBreakpoints.PROP_TYPE, IBreakpoints.TYPE_AUTO); } } return m; } /** * Filter given array of scope IDs of the form sessionId/contextId * to those applicable to the given channel. */ private String[] filterContextIds(IChannel channel, String[] scopeIds) { String sessionId = getSessionId(channel); List<String> contextIds = new ArrayList<String>(); for (String scopeId : scopeIds) { if (scopeId.length() == 0) continue; int slash = scopeId.indexOf('/'); if (slash < 0) { contextIds.add(scopeId); } else if (sessionId != null && sessionId.equals(scopeId.substring(0, slash))) { contextIds.add(scopeId.substring(slash+1)); } } return (String[]) contextIds.toArray(new String[contextIds.size()]); } /** * @return launch config name for given channel or <code>null</code> */ private String getSessionId(IChannel channel) { ILaunch[] launches = DebugPlugin.getDefault().getLaunchManager().getLaunches(); for (ILaunch launch : launches) { if (launch instanceof TCFLaunch) { if (channel == ((TCFLaunch) launch).getChannel()) { ILaunchConfiguration lc = launch.getLaunchConfiguration(); return lc != null ? lc.getName() : null; } } } return null; } }