blob: 2cc58e5843bb0e270a2c8ad7ccca78a46ce3152d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007-2021 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 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.internal.debug.ui.model;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerInputUpdate;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.memory.IMemoryRenderingSite;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.tcf.debug.ui.ITCFDebugUIConstants;
import org.eclipse.tcf.debug.ui.ITCFExecContext;
import org.eclipse.tcf.internal.debug.actions.TCFAction;
import org.eclipse.tcf.internal.debug.model.TCFBreakpointsModel;
import org.eclipse.tcf.internal.debug.model.TCFContextState;
import org.eclipse.tcf.internal.debug.model.TCFFunctionRef;
import org.eclipse.tcf.internal.debug.model.TCFSourceRef;
import org.eclipse.tcf.internal.debug.model.TCFSymFileRef;
import org.eclipse.tcf.internal.debug.ui.ColorCache;
import org.eclipse.tcf.internal.debug.ui.ImageCache;
import org.eclipse.tcf.protocol.IErrorReport;
import org.eclipse.tcf.protocol.IToken;
import org.eclipse.tcf.protocol.JSON;
import org.eclipse.tcf.protocol.Protocol;
import org.eclipse.tcf.services.IContextReset;
import org.eclipse.tcf.services.ILineNumbers;
import org.eclipse.tcf.services.IMemory;
import org.eclipse.tcf.services.IMemoryMap;
import org.eclipse.tcf.services.IProcesses;
import org.eclipse.tcf.services.IRunControl;
import org.eclipse.tcf.services.ISymbols;
import org.eclipse.tcf.util.TCFDataCache;
import org.eclipse.ui.IWorkbenchPart;
public class TCFNodeExecContext extends TCFNode implements ISymbolOwner, ITCFExecContext {
private final TCFChildrenExecContext children_exec;
private final TCFChildrenStackTrace children_stack;
private final TCFChildrenRegisters children_regs;
private final TCFChildrenExpressions children_exps;
private final TCFChildrenHoverExpressions children_hover_exps;
private final TCFChildrenLogExpressions children_log_exps;
private final TCFChildrenModules children_modules;
private final TCFChildrenContextQuery children_query;
private final TCFData<IMemory.MemoryContext> mem_context;
private final TCFData<IRunControl.RunControlContext> run_context;
private final TCFData<MemoryRegion[]> memory_map;
private final TCFData<IProcesses.ProcessContext> prs_context;
private final TCFData<TCFContextState> state;
private final TCFData<TCFContextState> min_state;
private final TCFData<BigInteger> address; // Current PC as BigInteger
private final TCFData<Collection<Map<String,Object>>> signal_list;
private final TCFData<SignalMask[]> signal_mask;
private final TCFData<TCFNodeExecContext> memory_node;
private final TCFData<TCFNodeExecContext> symbols_node;
private final TCFData<String> full_name;
private final TCFData<Collection<Map<String,Object>>> reset_capabilities;
private LinkedHashMap<BigInteger,TCFDataCache<TCFSymFileRef>> syms_info_lookup_cache;
private LinkedHashMap<BigInteger,TCFDataCache<TCFSourceRef>> line_info_lookup_cache;
private LinkedHashMap<BigInteger,TCFDataCache<TCFFunctionRef>> func_info_lookup_cache;
private LookupCacheTimer lookup_cache_timer;
private int mem_seq_no;
private int exe_seq_no;
private static final TCFNode[] empty_node_array = new TCFNode[0];
/*
* LookupCacheTimer is executed periodically to dispose least-recently
* accessed entries in line_info_lookup_cache and func_info_lookup_cache.
* The timer disposes itself when both caches become empty.
*/
private class LookupCacheTimer implements Runnable {
LookupCacheTimer() {
Protocol.invokeLater(4000, this);
}
public void run() {
if (isDisposed()) return;
if (syms_info_lookup_cache != null) {
BigInteger addr = syms_info_lookup_cache.keySet().iterator().next();
TCFDataCache<?> cache = syms_info_lookup_cache.get(addr);
if (!cache.isPending()) {
syms_info_lookup_cache.remove(addr).dispose();
if (syms_info_lookup_cache.size() == 0) syms_info_lookup_cache = null;
}
}
if (line_info_lookup_cache != null) {
BigInteger addr = line_info_lookup_cache.keySet().iterator().next();
TCFDataCache<?> cache = line_info_lookup_cache.get(addr);
if (!cache.isPending()) {
line_info_lookup_cache.remove(addr).dispose();
if (line_info_lookup_cache.size() == 0) line_info_lookup_cache = null;
}
}
if (func_info_lookup_cache != null) {
BigInteger addr = func_info_lookup_cache.keySet().iterator().next();
TCFDataCache<?> cache = func_info_lookup_cache.get(addr);
if (!cache.isPending()) {
func_info_lookup_cache.remove(addr).dispose();
if (func_info_lookup_cache.size() == 0) func_info_lookup_cache = null;
}
}
if (syms_info_lookup_cache == null && line_info_lookup_cache == null && func_info_lookup_cache == null) {
lookup_cache_timer = null;
}
else {
Protocol.invokeLater(2500, this);
}
}
}
public static class ChildrenStateInfo {
public boolean running;
public boolean suspended;
public boolean not_active;
public boolean breakpoint;
}
private final Map<String,TCFNodeSymbol> symbols = new HashMap<String,TCFNodeSymbol>();
private int resumed_cnt;
private boolean resume_pending;
private boolean resumed_by_action;
private TCFNode[] last_stack_trace;
private TCFNode[] last_children_list;
private String last_label;
private ImageDescriptor last_image;
private ChildrenStateInfo last_children_state_info;
private boolean delayed_children_list_delta;
/**
* Wrapper class for IMemoryMap.MemoryRegion.
* The class help to search memory region by address by
* providing contains() method.
*/
public static class MemoryRegion {
private final BigInteger addr_start;
private final BigInteger addr_end;
public final IMemoryMap.MemoryRegion region;
private MemoryRegion(IMemoryMap.MemoryRegion region) {
this.region = region;
Number addr = region.getAddress();
Number size = region.getSize();
if (addr == null || size == null) {
addr_start = null;
addr_end = null;
}
else {
addr_start = JSON.toBigInteger(addr);
addr_end = addr_start.add(JSON.toBigInteger(size));
}
}
public boolean contains(BigInteger addr) {
return
addr_start != null && addr_end != null &&
addr_start.compareTo(addr) <= 0 &&
addr_end.compareTo(addr) > 0;
}
@Override
public String toString() {
return region.getProperties().toString();
}
}
public static class SignalMask {
protected Map<String,Object> props;
protected boolean dont_stop;
protected boolean dont_pass;
protected boolean pending;
public Number getIndex() {
return (Number)props.get(IProcesses.SIG_INDEX);
}
public Number getCode() {
return (Number)props.get(IProcesses.SIG_CODE);
}
public Map<String,Object> getProperties() {
return props;
}
public boolean isDontStop() {
return dont_stop;
}
public boolean isDontPass() {
return dont_pass;
}
public boolean isPending() {
return pending;
}
@Override
public String toString() {
StringBuffer bf = new StringBuffer();
bf.append("[attrs=");
bf.append(props.toString());
if (dont_stop) bf.append(",don't stop");
if (dont_pass) bf.append(",don't pass");
if (pending) bf.append(",pending");
bf.append(']');
return bf.toString();
}
}
TCFNodeExecContext(TCFNode parent, final String id) {
super(parent, id);
children_exec = new TCFChildrenExecContext(this);
children_stack = new TCFChildrenStackTrace(this);
children_regs = new TCFChildrenRegisters(this);
children_exps = new TCFChildrenExpressions(this);
children_hover_exps = new TCFChildrenHoverExpressions(this);
children_log_exps = new TCFChildrenLogExpressions(this);
children_modules = new TCFChildrenModules(this);
children_query = new TCFChildrenContextQuery(this);
mem_context = new TCFData<IMemory.MemoryContext>(channel) {
@Override
protected boolean startDataRetrieval() {
assert command == null;
IMemory mem = launch.getService(IMemory.class);
if (mem == null) {
set(null, null, null);
return true;
}
command = mem.getContext(id, new IMemory.DoneGetContext() {
public void doneGetContext(IToken token, Exception error, IMemory.MemoryContext context) {
set(token, error, context);
}
});
return false;
}
};
run_context = new TCFData<IRunControl.RunControlContext>(channel) {
@Override
protected boolean startDataRetrieval() {
assert command == null;
IRunControl run = launch.getService(IRunControl.class);
if (run == null) {
set(null, null, null);
return true;
}
command = run.getContext(id, new IRunControl.DoneGetContext() {
public void doneGetContext(IToken token, Exception error, IRunControl.RunControlContext context) {
if (context != null) model.getContextMap().put(id, context);
set(token, error, context);
}
});
return false;
}
};
prs_context = new TCFData<IProcesses.ProcessContext>(channel) {
@Override
protected boolean startDataRetrieval() {
assert command == null;
IProcesses prs = launch.getService(IProcesses.class);
if (prs == null) {
set(null, null, null);
return true;
}
command = prs.getContext(id, new IProcesses.DoneGetContext() {
public void doneGetContext(IToken token, Exception error, IProcesses.ProcessContext context) {
set(token, error, context);
}
});
return false;
}
};
memory_map = new TCFData<MemoryRegion[]>(channel) {
@Override
protected boolean startDataRetrieval() {
assert command == null;
IMemoryMap mmap = launch.getService(IMemoryMap.class);
if (mmap == null) {
set(null, null, null);
return true;
}
command = mmap.get(id, new IMemoryMap.DoneGet() {
public void doneGet(IToken token, Exception error, IMemoryMap.MemoryRegion[] map) {
MemoryRegion[] arr = null;
if (map != null) {
int i = 0;
arr = new MemoryRegion[map.length];
for (IMemoryMap.MemoryRegion r : map) arr[i++] = new MemoryRegion(r);
}
set(token, error, arr);
}
});
return false;
}
};
state = new TCFData<TCFContextState>(channel) {
@Override
protected boolean startDataRetrieval() {
assert command == null;
if (!run_context.validate(this)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx == null || !ctx.hasState()) {
set(null, null, null);
return true;
}
command = ctx.getState(new IRunControl.DoneGetState() {
public void doneGetState(IToken token, Exception error, boolean suspended, String pc, String reason, Map<String,Object> params) {
TCFContextState s = new TCFContextState();
s.is_suspended = suspended;
s.suspend_pc = pc;
s.suspend_reason = reason;
s.suspend_params = params;
set(token, error, s);
}
});
return false;
}
};
min_state = new TCFData<TCFContextState>(channel) {
@Override
protected boolean startDataRetrieval() {
assert command == null;
if (!run_context.validate(this)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx == null || !ctx.hasState()) {
set(null, null, null);
return true;
}
if (model.no_min_state || state.isValid()) {
if (!state.validate(this)) return false;
Throwable e = state.getError();
TCFContextState s = state.getData();
TCFContextState m = null;
if (s != null) {
m = new TCFContextState();
m.is_suspended = s.is_suspended;
m.suspend_reason = s.suspend_reason;
m.suspend_params = s.suspend_params;
}
set(null, e, m);
return true;
}
command = ctx.getMinState(new IRunControl.DoneGetMinState() {
public void doneGetMinState(IToken token, Exception error, boolean suspended, String reason, Map<String,Object> params) {
if (error instanceof IErrorReport && ((IErrorReport)error).getErrorCode() == IErrorReport.TCF_ERROR_INV_COMMAND) {
model.no_min_state = true;
command = null;
validate();
return;
}
TCFContextState m = new TCFContextState();
m.is_suspended = suspended;
m.suspend_reason = reason;
m.suspend_params = params;
set(token, error, m);
}
});
return false;
}
};
address = new TCFData<BigInteger>(channel) {
@Override
protected boolean startDataRetrieval() {
if (!run_context.validate(this)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx == null || !ctx.hasState()) {
set(null, run_context.getError(), null);
return true;
}
if (!state.validate(this)) return false;
TCFContextState s = state.getData();
if (s == null) {
set(null, state.getError(), null);
return true;
}
if (!s.is_suspended || s.suspend_pc == null) {
set(null, null, null);
return true;
}
set(null, null, new BigInteger(s.suspend_pc));
return true;
}
};
signal_list = new TCFData<Collection<Map<String,Object>>>(channel) {
@Override
protected boolean startDataRetrieval() {
IProcesses prs = channel.getRemoteService(IProcesses.class);
if (prs == null) {
set(null, null, null);
return true;
}
command = prs.getSignalList(id, new IProcesses.DoneGetSignalList() {
public void doneGetSignalList(IToken token, Exception error, Collection<Map<String, Object>> list) {
set(token, error, list);
}
});
return false;
}
};
signal_mask = new TCFData<SignalMask[]>(channel) {
@Override
protected boolean startDataRetrieval() {
if (!signal_list.validate(this)) return false;
IProcesses prs = channel.getRemoteService(IProcesses.class);
final Collection<Map<String,Object>> sigs = signal_list.getData();
if (prs == null || sigs == null) {
set(null, signal_list.getError(), null);
return true;
}
command = prs.getSignalMask(id, new IProcesses.DoneGetSignalMaskSets() {
public void doneGetSignalMask(IToken token, Exception error,
Set<Integer> dont_stop, Set<Integer> dont_pass, Set<Integer> pending) {
int n = 0;
SignalMask[] list = new SignalMask[sigs.size()];
for (Map<String,Object> m : sigs) {
SignalMask s = list[n++] = new SignalMask();
s.props = m;
int i = s.getIndex().intValue();
s.dont_stop = dont_stop.contains(i);
s.dont_pass = dont_pass.contains(i);
s.pending = pending.contains(i);
}
set(token, error, list);
}
});
return false;
}
};
memory_node = new TCFData<TCFNodeExecContext>(channel) {
@Override
protected boolean startDataRetrieval() {
String mem_id = null;
if (!run_context.validate(this)) return false;
Throwable err = run_context.getError();
if (err == null) {
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null) mem_id = ctx.getProcessID();
}
if (err != null) {
set(null, err, null);
}
else if (mem_id == null) {
set(null, new Exception("Context does not provide memory access"), null);
}
else {
if (!model.createNode(mem_id, this)) return false;
if (!isValid()) set(null, null, (TCFNodeExecContext)model.getNode(mem_id));
}
return true;
}
};
symbols_node = new TCFData<TCFNodeExecContext>(channel) {
@Override
protected boolean startDataRetrieval() {
String syms_id = null;
if (!run_context.validate(this)) return false;
Throwable err = run_context.getError();
if (err == null) {
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null) {
syms_id = ctx.getSymbolsGroup();
if (syms_id == null) syms_id = ctx.getProcessID();
}
}
if (err != null) {
set(null, err, null);
}
else if (syms_id == null) {
set(null, new Exception("Context does not support symbol groups"), null);
}
else {
if (!model.createNode(syms_id, this)) return false;
if (!isValid()) set(null, null, (TCFNodeExecContext)model.getNode(syms_id));
}
return true;
}
};
full_name = new TCFData<String>(channel) {
@Override
protected boolean startDataRetrieval() {
if (!run_context.validate(this)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
String res = null;
if (ctx != null) {
res = ctx.getName();
if (res == null) {
res = ctx.getID();
}
else {
// Add ancestor names
TCFNodeExecContext p = TCFNodeExecContext.this;
ArrayList<String> lst = new ArrayList<String>();
lst.add(res);
while (p.parent instanceof TCFNodeExecContext) {
p = (TCFNodeExecContext)p.parent;
TCFDataCache<IRunControl.RunControlContext> run_ctx_cache = p.run_context;
if (!run_ctx_cache.validate(this)) return false;
IRunControl.RunControlContext run_ctx_data = run_ctx_cache.getData();
String name = null;
if (run_ctx_data != null) name = run_ctx_data.getName();
if (name == null) name = "";
lst.add(name);
}
StringBuffer bf = new StringBuffer();
for (int i = lst.size(); i > 0; i--) {
String name = lst.get(i - 1);
boolean quote = name.indexOf('/') >= 0;
bf.append('/');
if (quote) bf.append('"');
bf.append(name);
if (quote) bf.append('"');
}
res = bf.toString();
}
}
set(null, null, res);
return true;
}
};
reset_capabilities = new TCFData<Collection<Map<String, Object>>>(channel) {
@Override
protected boolean startDataRetrieval() {
IContextReset reset = launch.getService(IContextReset.class);
if (reset == null) {
set(null, null, null);
return true;
}
command = reset.getCapabilities(id, new IContextReset.DoneGetCapabilities() {
@Override
public void doneGetCapabilities(IToken token, Exception error, Collection<Map<String, Object>> capabilities) {
set(token, error, capabilities);
}
});
return false;
}
};
TCFMemoryBlock.onMemoryNodeCreated(this);
updateTerminal();
}
@Override
void dispose() {
assert !isDisposed();
ArrayList<TCFNodeSymbol> l = new ArrayList<TCFNodeSymbol>(symbols.values());
for (TCFNodeSymbol s : l) s.dispose();
assert symbols.size() == 0;
super.dispose();
}
void setMemSeqNo(int no) {
mem_seq_no = no;
}
void setExeSeqNo(int no) {
exe_seq_no = no;
}
TCFChildren getHoverExpressionCache(String expression) {
children_hover_exps.setExpression(expression);
return children_hover_exps;
}
public TCFChildrenLogExpressions getLogExpressionCache() {
return children_log_exps;
}
void setRunContext(IRunControl.RunControlContext ctx) {
run_context.reset(ctx);
}
void setProcessContext(IProcesses.ProcessContext ctx) {
prs_context.reset(ctx);
}
void setMemoryContext(IMemory.MemoryContext ctx) {
mem_context.reset(ctx);
}
public TCFDataCache<TCFNodeExecContext> getSymbolsNode() {
return symbols_node;
}
public TCFDataCache<TCFNodeExecContext> getMemoryNode() {
return memory_node;
}
public TCFDataCache<MemoryRegion[]> getMemoryMap() {
return memory_map;
}
public TCFDataCache<Collection<Map<String,Object>>> getSignalList() {
return signal_list;
}
public TCFDataCache<SignalMask[]> getSignalMask() {
return signal_mask;
}
public TCFDataCache<TCFSymFileRef> getSymFileInfo(final BigInteger addr) {
if (addr == null || isDisposed()) return null;
TCFDataCache<TCFSymFileRef> ref_cache;
if (syms_info_lookup_cache != null) {
ref_cache = syms_info_lookup_cache.get(addr);
if (ref_cache != null) return ref_cache;
}
final ISymbols syms = launch.getService(ISymbols.class);
if (syms == null) return null;
if (syms_info_lookup_cache == null) {
syms_info_lookup_cache = new LinkedHashMap<BigInteger,TCFDataCache<TCFSymFileRef>>(11, 0.75f, true);
if (lookup_cache_timer == null) lookup_cache_timer = new LookupCacheTimer();
}
syms_info_lookup_cache.put(addr, ref_cache = new TCFData<TCFSymFileRef>(channel) {
@Override
protected boolean startDataRetrieval() {
if (!memory_node.validate(this)) return false;
IMemory.MemoryContext mem_data = null;
TCFNodeExecContext mem = memory_node.getData();
if (mem != null) {
TCFDataCache<IMemory.MemoryContext> mem_cache = mem.mem_context;
if (!mem_cache.validate(this)) return false;
mem_data = mem_cache.getData();
}
final TCFSymFileRef ref_data = new TCFSymFileRef();
if (mem_data != null) {
ref_data.context_id = mem_data.getID();
ref_data.address_size = mem_data.getAddressSize();
}
command = syms.getSymFileInfo(ref_data.context_id, addr, new ISymbols.DoneGetSymFileInfo() {
public void doneGetSymFileInfo(IToken token, Exception error, Map<String,Object> props) {
ref_data.address = addr;
ref_data.error = error;
ref_data.props = props;
set(token, null, ref_data);
}
});
return false;
}
});
return ref_cache;
}
public TCFDataCache<TCFSourceRef> getLineInfo(final BigInteger addr) {
if (isDisposed()) return null;
TCFDataCache<TCFSourceRef> ref_cache;
if (line_info_lookup_cache != null) {
ref_cache = line_info_lookup_cache.get(addr);
if (ref_cache != null) return ref_cache;
}
final ILineNumbers ln = launch.getService(ILineNumbers.class);
if (ln == null) return null;
final BigInteger n0 = addr;
final BigInteger n1 = n0.add(BigInteger.valueOf(1));
if (line_info_lookup_cache == null) {
line_info_lookup_cache = new LinkedHashMap<BigInteger,TCFDataCache<TCFSourceRef>>(11, 0.75f, true);
if (lookup_cache_timer == null) lookup_cache_timer = new LookupCacheTimer();
}
line_info_lookup_cache.put(addr, ref_cache = new TCFData<TCFSourceRef>(channel) {
@Override
protected boolean startDataRetrieval() {
if (!memory_node.validate(this)) return false;
IMemory.MemoryContext mem_data = null;
TCFNodeExecContext mem = memory_node.getData();
if (mem != null) {
TCFDataCache<IMemory.MemoryContext> mem_cache = mem.mem_context;
if (!mem_cache.validate(this)) return false;
mem_data = mem_cache.getData();
}
final TCFSourceRef ref_data = new TCFSourceRef();
if (mem_data != null) {
ref_data.context_id = mem_data.getID();
ref_data.address_size = mem_data.getAddressSize();
}
command = ln.mapToSource(id, n0, n1, new ILineNumbers.DoneMapToSource() {
public void doneMapToSource(IToken token, Exception error, ILineNumbers.CodeArea[] areas) {
ref_data.address = addr;
if (error == null && areas != null && areas.length > 0) {
for (ILineNumbers.CodeArea area : areas) {
BigInteger a0 = JSON.toBigInteger(area.start_address);
BigInteger a1 = JSON.toBigInteger(area.end_address);
if (n0.compareTo(a0) >= 0 && n0.compareTo(a1) < 0) {
boolean add = true;
if (ref_data.area != null) {
BigInteger b0 = JSON.toBigInteger(ref_data.area.start_address);
BigInteger b1 = JSON.toBigInteger(ref_data.area.end_address);
add = a1.subtract(a0).compareTo(b1.subtract(b0)) < 0;
}
if (add) {
if (area.start_address != a0 || area.end_address != a1) {
area = new ILineNumbers.CodeArea(area.directory, area.file,
area.start_line, area.start_column,
area.end_line, area.end_column,
a0, a1, area.isa,
area.is_statement, area.basic_block,
area.prologue_end, area.epilogue_begin);
}
ref_data.area = area;
}
}
}
}
ref_data.error = error;
set(token, null, ref_data);
}
});
return false;
}
});
return ref_cache;
}
public TCFDataCache<TCFFunctionRef> getFuncInfo(final BigInteger addr) {
if (isDisposed()) return null;
TCFDataCache<TCFFunctionRef> ref_cache;
if (func_info_lookup_cache != null) {
ref_cache = func_info_lookup_cache.get(addr);
if (ref_cache != null) return ref_cache;
}
final ISymbols syms = launch.getService(ISymbols.class);
if (syms == null) return null;
if (func_info_lookup_cache == null) {
func_info_lookup_cache = new LinkedHashMap<BigInteger,TCFDataCache<TCFFunctionRef>>(11, 0.75f, true);
if (lookup_cache_timer == null) lookup_cache_timer = new LookupCacheTimer();
}
func_info_lookup_cache.put(addr, ref_cache = new TCFData<TCFFunctionRef>(channel) {
@Override
protected boolean startDataRetrieval() {
if (!memory_node.validate(this)) return false;
IMemory.MemoryContext mem_data = null;
TCFNodeExecContext mem = memory_node.getData();
if (mem != null) {
TCFDataCache<IMemory.MemoryContext> mem_cache = mem.mem_context;
if (!mem_cache.validate(this)) return false;
mem_data = mem_cache.getData();
}
final TCFFunctionRef ref_data = new TCFFunctionRef();
if (mem_data != null) {
ref_data.context_id = mem_data.getID();
ref_data.address_size = mem_data.getAddressSize();
}
ref_data.address = addr;
command = syms.findByAddr(id, addr, new ISymbols.DoneFind() {
public void doneFind(IToken token, Exception error, String symbol_id) {
ref_data.error = error;
ref_data.symbol_id = symbol_id;
set(token, null, ref_data);
}
});
return false;
}
});
return ref_cache;
}
private void clearLookupCaches() {
if (syms_info_lookup_cache != null) {
Iterator<TCFDataCache<TCFSymFileRef>> i = syms_info_lookup_cache.values().iterator();
while (i.hasNext()) {
TCFDataCache<TCFSymFileRef> cache = i.next();
if (cache.isPending()) continue;
cache.dispose();
i.remove();
}
if (syms_info_lookup_cache.size() == 0) syms_info_lookup_cache = null;
}
if (line_info_lookup_cache != null) {
Iterator<TCFDataCache<TCFSourceRef>> i = line_info_lookup_cache.values().iterator();
while (i.hasNext()) {
TCFDataCache<TCFSourceRef> cache = i.next();
if (cache.isPending()) continue;
cache.dispose();
i.remove();
}
if (line_info_lookup_cache.size() == 0) line_info_lookup_cache = null;
}
if (func_info_lookup_cache != null) {
Iterator<TCFDataCache<TCFFunctionRef>> i = func_info_lookup_cache.values().iterator();
while (i.hasNext()) {
TCFDataCache<TCFFunctionRef> cache = i.next();
if (cache.isPending()) continue;
cache.dispose();
i.remove();
}
if (func_info_lookup_cache.size() == 0) func_info_lookup_cache = null;
}
}
private void updateTerminal() {
new Runnable() {
@Override
public void run() {
if (isDisposed()) return;
if (!run_context.validate(this)) return;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null) {
@SuppressWarnings("unchecked")
Map<String,Object> uart = (Map<String,Object>)ctx.getProperties().get("UART");
if (uart != null) launch.openUartStreams(id, uart);
}
}
}.run();
}
@Override
public TCFNode getParent(IPresentationContext ctx) {
assert Protocol.isDispatchThread();
if (IDebugUIConstants.ID_DEBUG_VIEW.equals(ctx.getId())) {
Set<String> ids = launch.getContextFilter();
if (ids != null) {
if (ids.contains(id)) return model.getRootNode();
if (parent instanceof TCFNodeLaunch) return null;
}
}
return parent;
}
public TCFDataCache<IRunControl.RunControlContext> getRunContext() {
return run_context;
}
public TCFDataCache<IProcesses.ProcessContext> getProcessContext() {
return prs_context;
}
public TCFDataCache<IMemory.MemoryContext> getMemoryContext() {
return mem_context;
}
public TCFDataCache<BigInteger> getAddress() {
return address;
}
public TCFDataCache<TCFContextState> getState() {
return state;
}
public TCFDataCache<TCFContextState> getMinState() {
return min_state;
}
public TCFChildrenStackTrace getStackTrace() {
return children_stack;
}
public TCFChildren getRegisters() {
return children_regs;
}
public TCFChildren getModules() {
return children_modules;
}
public TCFChildren getChildren() {
return children_exec;
}
public TCFNodeStackFrame getLastTopFrame() {
if (!resume_pending) return null;
if (last_stack_trace == null || last_stack_trace.length == 0) return null;
return (TCFNodeStackFrame)last_stack_trace[0];
}
public TCFNodeStackFrame getViewBottomFrame() {
if (last_stack_trace == null || last_stack_trace.length == 0) return null;
return (TCFNodeStackFrame)last_stack_trace[last_stack_trace.length - 1];
}
/**
* Get context full name - including all ancestor names.
* Return context ID if the context does not have a name.
* @return cache item with the context full name.
*/
public TCFDataCache<String> getFullName() {
return full_name;
}
public TCFDataCache<Collection<Map<String, Object>>> getResetCapabilities() {
return reset_capabilities;
}
public void reset(String reset_type, Map<String, Object> params) {
IContextReset ctx_reset = launch.getService(IContextReset.class);
if (ctx_reset != null) {
ctx_reset.reset(id, reset_type, params, new IContextReset.DoneReset() {
@Override
public void doneReset(IToken token, Exception error) {
if (error != null) {
model.showMessageBox("Cannot reset context", error);
}
}
});
}
}
public void addSymbol(TCFNodeSymbol s) {
assert symbols.get(s.id) == null;
symbols.put(s.id, s);
}
public void removeSymbol(TCFNodeSymbol s) {
assert symbols.get(s.id) == s;
symbols.remove(s.id);
}
/**
* Return true if this context cannot be accessed because it is not active.
* Not active means the target is suspended, but this context is not one that is
* currently scheduled to run on a target CPU, and the debuggers don't support
* access to register values and other properties of such contexts.
*/
public boolean isNotActive() {
TCFContextState state_data = state.getData();
if (state_data != null) return state_data.isNotActive();
return false;
}
private boolean okToShowLastStack() {
if (last_stack_trace == null) return false;
return resume_pending || (launch.getContextActionsCount(id) > 0 && model.getDelayStackUpdateUtilLastStep());
}
private boolean okToHideStack() {
TCFAction action = model.getActiveAction(id);
if (action != null && action.showRunning()) return true;
TCFContextState state_data = min_state.getData();
if (state_data == null) return true;
assert state_data.suspend_pc == null;
if (!state_data.is_suspended) return true;
if (state_data.isNotActive()) return true;
return false;
}
@Override
protected boolean getData(IChildrenCountUpdate result, Runnable done) {
TCFChildren children = null;
String view_id = result.getPresentationContext().getId();
if (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && ctx.hasState()) {
if (okToShowLastStack()) {
result.setChildCount(last_stack_trace.length);
return true;
}
if (!min_state.validate(done)) return false;
if (okToHideStack()) {
last_stack_trace = empty_node_array;
result.setChildCount(0);
return true;
}
children = children_stack;
}
else {
if (!model.getAutoChildrenListUpdates() && last_children_list != null) {
result.setChildCount(last_children_list.length);
return true;
}
children = children_exec;
}
}
else if (IDebugUIConstants.ID_REGISTER_VIEW.equals(view_id)) {
children = children_regs;
}
else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null) children = children_exps;
}
else if (TCFModel.ID_EXPRESSION_HOVER.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && ctx.hasState()) children = children_hover_exps;
}
else if (IDebugUIConstants.ID_MODULE_VIEW.equals(view_id)) {
if (!mem_context.validate(done)) return false;
IMemory.MemoryContext ctx = mem_context.getData();
if (ctx != null) children = children_modules;
}
else if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) {
if (!children_query.setQuery(result, done)) return false;
children = children_query;
}
if (children != null) {
if (!children.validate(done)) return false;
if (children == children_stack) last_stack_trace = children_stack.toArray();
if (children == children_exec) last_children_list = children_exec.toArray();
result.setChildCount(children.size());
}
else {
result.setChildCount(0);
}
return true;
}
private void setResultChildren(IChildrenUpdate result, TCFNode[] arr) {
int offset = 0;
int r_offset = result.getOffset();
int r_length = result.getLength();
for (TCFNode n : arr) {
if (offset >= r_offset && offset < r_offset + r_length) {
result.setChild(n, offset);
}
offset++;
}
}
@Override
protected boolean getData(IChildrenUpdate result, Runnable done) {
TCFChildren children = null;
String view_id = result.getPresentationContext().getId();
if (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && ctx.hasState()) {
if (okToShowLastStack()) {
setResultChildren(result, last_stack_trace);
return true;
}
if (!min_state.validate(done)) return false;
if (okToHideStack()) {
last_stack_trace = empty_node_array;
return true;
}
// Force creation of register nodes.
// It helps dispatching of registerChanged events to stack frames.
if (!children_regs.validate(done)) return false;
children = children_stack;
}
else {
if (!model.getAutoChildrenListUpdates() && last_children_list != null) {
setResultChildren(result, last_children_list);
return true;
}
children = children_exec;
}
}
else if (IDebugUIConstants.ID_REGISTER_VIEW.equals(view_id)) {
children = children_regs;
}
else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null) children = children_exps;
}
else if (TCFModel.ID_EXPRESSION_HOVER.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && ctx.hasState()) children = children_hover_exps;
}
else if (IDebugUIConstants.ID_MODULE_VIEW.equals(view_id)) {
if (!mem_context.validate(done)) return false;
IMemory.MemoryContext ctx = mem_context.getData();
if (ctx != null) children = children_modules;
}
else if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) {
if (!children_query.setQuery(result, done)) return false;
children = children_query;
}
if (children == null) return true;
if (children == children_stack) {
if (!children.validate(done)) return false;
last_stack_trace = children_stack.toArray();
}
if (children == children_exec) {
if (!children.validate(done)) return false;
last_children_list = children_exec.toArray();
}
return children.getData(result, done);
}
@Override
protected boolean getData(IHasChildrenUpdate result, Runnable done) {
TCFChildren children = null;
String view_id = result.getPresentationContext().getId();
if (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && ctx.hasState()) {
if (okToShowLastStack()) {
result.setHasChilren(last_stack_trace.length > 0);
return true;
}
if (!min_state.validate(done)) return false;
if (okToHideStack()) {
last_stack_trace = empty_node_array;
result.setHasChilren(false);
return true;
}
Boolean has_children = children_stack.checkHasChildren(done);
if (has_children == null) return false;
result.setHasChilren(has_children);
return true;
}
else {
if (!model.getAutoChildrenListUpdates() && last_children_list != null) {
result.setHasChilren(last_children_list.length > 0);
return true;
}
children = children_exec;
}
}
else if (IDebugUIConstants.ID_REGISTER_VIEW.equals(view_id)) {
children = children_regs;
}
else if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null) children = children_exps;
}
else if (TCFModel.ID_EXPRESSION_HOVER.equals(view_id)) {
if (!run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && ctx.hasState()) children = children_hover_exps;
}
else if (IDebugUIConstants.ID_MODULE_VIEW.equals(view_id)) {
if (!mem_context.validate(done)) return false;
IMemory.MemoryContext ctx = mem_context.getData();
if (ctx != null) children = children_modules;
}
else if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) {
if (!children_query.setQuery(result, done)) return false;
children = children_query;
}
if (children != null) {
if (!children.validate(done)) return false;
if (children == children_stack) last_stack_trace = children_stack.toArray();
if (children == children_exec) last_children_list = children_exec.toArray();
result.setHasChilren(children.size() > 0);
}
else {
result.setHasChilren(false);
}
return true;
}
private String addStateName(StringBuffer label, TCFContextState state_data) {
String image_name = ImageCache.IMG_THREAD_UNKNOWN_STATE;
assert !state_data.is_suspended;
if (state_data.suspend_params != null) {
String name = (String)state_data.suspend_params.get(IRunControl.STATE_NAME);
if (name != null) {
label.append(" (");
label.append(name);
label.append(")");
return image_name;
}
}
if (state_data.isReversing()) {
image_name = ImageCache.IMG_THREAD_REVERSING;
label.append(" (Reversing)");
}
else {
image_name = ImageCache.IMG_THREAD_RUNNNIG;
label.append(" (Running)");
}
return image_name;
}
@Override
protected boolean getData(ILabelUpdate result, Runnable done) {
if (!run_context.validate(done)) return false;
String image_name = null;
boolean suspended_by_bp = false;
ChildrenStateInfo children_state_info = null;
StringBuffer label = new StringBuffer();
Throwable error = run_context.getError();
if (error != null) {
result.setForeground(ColorCache.rgb_error, 0);
label.append(id);
label.append(": ");
label.append(TCFModel.getErrorMessage(error, false));
}
else {
String view_id = result.getPresentationContext().getId();
if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) {
TCFChildrenContextQuery.Descendants des = TCFChildrenContextQuery.getDescendants(this, result, done);
if (des == null) return false;
if (des.map != null && des.map.size() > 0) {
label.append("(");
label.append(des.map.size());
label.append(") ");
}
if (!des.include_parent) result.setForeground(ColorCache.rgb_disabled, 0);
}
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx == null) {
label.append(id);
}
else {
String nm = ctx.getName();
if (nm == null && !ctx.hasState()) {
String prs = ctx.getProcessID();
if (prs != null) {
if (!prs_context.validate(done)) return false;
IProcesses.ProcessContext pctx = prs_context.getData();
if (pctx != null) nm = pctx.getName();
}
}
label.append(nm != null ? nm : id);
Object info = ctx.getProperties().get("AdditionalInfo");
if (info != null) label.append(info.toString());
if (TCFModel.ID_PINNED_VIEW.equals(view_id) || ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) {
image_name = ctx.hasState() ? ImageCache.IMG_THREAD_UNKNOWN_STATE : ImageCache.IMG_PROCESS_RUNNING;
}
else if (ctx.hasState()) {
// Thread
TCFAction action = model.getActiveAction(id);
if (resume_pending && resumed_by_action || action != null) {
if (action != null && action.showRunning()) {
image_name = ImageCache.IMG_THREAD_RUNNNIG;
}
else {
if (!min_state.validate(done)) return false;
TCFContextState state_data = min_state.getData();
image_name = ImageCache.IMG_THREAD_UNKNOWN_STATE;
if (state_data != null) {
if (!state_data.is_suspended) {
image_name = addStateName(label, state_data);
}
else {
suspended_by_bp = IRunControl.REASON_BREAKPOINT.equals(state_data.suspend_reason);
}
}
if (resume_pending && last_label != null) {
result.setImageDescriptor(ImageCache.getImageDescriptor(image_name), 0);
result.setLabel(last_label, 0);
return true;
}
}
}
else if (resume_pending && last_label != null && last_image != null) {
result.setImageDescriptor(last_image, 0);
result.setLabel(last_label, 0);
return true;
}
else {
if (!min_state.validate(done)) return false;
TCFContextState state_data = min_state.getData();
if (state_data != null && state_data.isNotActive()) {
image_name = ImageCache.IMG_THREAD_NOT_ACTIVE;
label.append(" (Not active)");
if (state_data.suspend_reason != null && !state_data.suspend_reason.equals(IRunControl.REASON_USER_REQUEST)) {
label.append(" - ");
label.append(state_data.suspend_reason);
}
}
else {
image_name = ImageCache.IMG_THREAD_UNKNOWN_STATE;
if (state_data != null) {
if (!state_data.is_suspended) {
image_name = addStateName(label, state_data);
}
else {
image_name = ImageCache.IMG_THREAD_SUSPENDED;
String sig_name = null;
String bp_names = null;
String suspend_reason = model.getContextActionResult(id);
if (suspend_reason == null) suspend_reason = state_data.suspend_reason;
if (state_data.suspend_params != null) {
sig_name = (String)state_data.suspend_params.get(IRunControl.STATE_SIGNAL_DESCRIPTION);
if (sig_name == null) sig_name = (String)state_data.suspend_params.get(IRunControl.STATE_SIGNAL_NAME);
Object ids = state_data.suspend_params.get(IRunControl.STATE_BREAKPOINT_IDS);
if (ids != null) {
@SuppressWarnings("unchecked")
Collection<String> bp_ids = (Collection<String>)ids;
TCFBreakpointsModel bp_model = TCFBreakpointsModel.getBreakpointsModel();
for (String bp_id : bp_ids) {
IBreakpoint bp = bp_model.getBreakpoint(bp_id);
if (bp != null) {
String bp_name = null;
IMarker m = bp.getMarker();
if (m != null) {
bp_name = m.getAttribute(TCFBreakpointsModel.ATTR_ADDRESS, null);
if (bp_name == null) bp_name = m.getAttribute(TCFBreakpointsModel.ATTR_FUNCTION, null);
if (bp_name == null) bp_name = m.getAttribute(TCFBreakpointsModel.ATTR_EXPRESSION, null);
if (bp_name == null) {
String file = m.getAttribute(TCFBreakpointsModel.ATTR_REQESTED_FILE, null);
int line = m.getAttribute(TCFBreakpointsModel.ATTR_REQESTED_LINE, 0);
if (file == null) file = m.getAttribute(TCFBreakpointsModel.ATTR_FILE, null);
if (line == 0) line = m.getAttribute(TCFBreakpointsModel.ATTR_LINE, 0);
if (file != null && line > 0) {
bp_name = new Path(file).lastSegment() + ":" + line;
}
}
}
if (bp_name == null) bp_name = bp_id;
if (bp_names == null) bp_names = bp_name;
else bp_names = bp_names + ", " + bp_name;
}
}
}
}
if (suspend_reason == null) suspend_reason = "Suspended";
suspended_by_bp = IRunControl.REASON_BREAKPOINT.equals(suspend_reason) || bp_names != null;
label.append(" (");
label.append(suspend_reason);
if (IRunControl.REASON_SIGNAL.equals(suspend_reason) && sig_name != null) {
label.append(": ");
label.append(sig_name);
sig_name = null;
}
if (IRunControl.REASON_BREAKPOINT.equals(suspend_reason) && bp_names != null) {
label.append(": ");
label.append(bp_names);
bp_names = null;
}
if (sig_name != null) {
label.append("; ");
label.append(IRunControl.REASON_SIGNAL);
label.append(": ");
label.append(sig_name);
}
if (bp_names != null) {
label.append("; ");
label.append(IRunControl.REASON_BREAKPOINT);
label.append(": ");
label.append(bp_names);
}
label.append(")");
if (state_data.suspend_params != null) {
String prs = (String)state_data.suspend_params.get(IRunControl.STATE_CONTEXT);
if (prs != null) {
label.append(", ");
label.append(prs);
}
String cpu = (String)state_data.suspend_params.get(IRunControl.STATE_CPU);
if (cpu != null) {
label.append(", ");
label.append(cpu);
}
}
}
}
}
}
}
else {
// Thread container (process)
children_state_info = new ChildrenStateInfo();
if (!hasSuspendedChildren(children_state_info, done)) return false;
if (children_state_info.suspended) image_name = ImageCache.IMG_PROCESS_SUSPENDED;
else image_name = ImageCache.IMG_PROCESS_RUNNING;
suspended_by_bp = children_state_info.breakpoint;
}
}
}
last_children_state_info = children_state_info;
last_image = ImageCache.getImageDescriptor(image_name);
if (suspended_by_bp) last_image = ImageCache.addOverlay(last_image, ImageCache.IMG_BREAKPOINT_OVERLAY);
result.setImageDescriptor(last_image, 0);
result.setLabel(last_label = label.toString(), 0);
return true;
}
@Override
protected boolean getData(IViewerInputUpdate result, Runnable done) {
result.setInputElement(this);
String view_id = result.getPresentationContext().getId();
if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(view_id)) {
if (launch.getContextActionsCount(id) > 0 && model.getDelayStackUpdateUtilLastStep()) return true;
if (!children_stack.validate(done)) return false;
TCFNodeStackFrame frame = children_stack.getTopFrame();
if (frame != null) result.setInputElement(frame);
}
else if (IDebugUIConstants.ID_MODULE_VIEW.equals(view_id)) {
// TODO: need to post view input delta when memory context changes
TCFDataCache<TCFNodeExecContext> mem = model.searchMemoryContext(this);
if (mem == null) return true;
if (!mem.validate(done)) return false;
if (mem.getData() == null) return true;
result.setInputElement(mem.getData());
}
return true;
}
@Override
public void refresh(IWorkbenchPart part) {
if (part instanceof IMemoryRenderingSite) {
model.onMemoryChanged(id, false, false, false);
}
else {
super.refresh(part);
}
}
void postAllChangedDelta() {
postContentChangedDelta();
postStateChangedDelta();
}
void postContextAddedDelta() {
if (parent instanceof TCFNodeExecContext) {
TCFNodeExecContext exe = (TCFNodeExecContext)parent;
ChildrenStateInfo info = exe.last_children_state_info;
if (info != null) {
if (!model.getAutoChildrenListUpdates()) {
// Manual updates.
return;
}
if (!info.suspended && !info.not_active && model.getDelayChildrenListUpdates()) {
// Delay content update until a child is suspended.
exe.delayed_children_list_delta = true;
return;
}
}
}
for (TCFModelProxy p : model.getModelProxies()) {
String view_id = p.getPresentationContext().getId();
if (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id)) {
p.addDelta(this, IModelDelta.INSERTED);
}
else if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) {
p.addDelta(parent, IModelDelta.CONTENT);
}
}
}
private void postContextRemovedDelta() {
if (parent instanceof TCFNodeExecContext) {
TCFNodeExecContext exe = (TCFNodeExecContext)parent;
ChildrenStateInfo info = exe.last_children_state_info;
if (info != null) {
if (!model.getAutoChildrenListUpdates()) {
// Manual updates.
return;
}
if (!info.suspended && !info.not_active && model.getDelayChildrenListUpdates()) {
// Delay content update until a child is suspended.
exe.delayed_children_list_delta = true;
return;
}
}
}
for (TCFModelProxy p : model.getModelProxies()) {
String view_id = p.getPresentationContext().getId();
if (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id)) {
p.addDelta(this, IModelDelta.REMOVED);
}
else if (ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) {
p.addDelta(parent, IModelDelta.CONTENT);
}
}
// Update parent icon overlays
TCFNode n = parent;
while (n instanceof TCFNodeExecContext) {
TCFNodeExecContext e = (TCFNodeExecContext)n;
ChildrenStateInfo info = e.last_children_state_info;
if (info != null && info.suspended) e.postStateChangedDelta();
n = n.parent;
}
}
private void postContentChangedDelta() {
delayed_children_list_delta = false;
for (TCFModelProxy p : model.getModelProxies()) {
int flags = 0;
String view_id = p.getPresentationContext().getId();
if ( (IDebugUIConstants.ID_DEBUG_VIEW.equals(view_id) ||
ITCFDebugUIConstants.ID_CONTEXT_QUERY_VIEW.equals(view_id)) &&
(launch.getContextActionsCount(id) == 0 || !model.getDelayStackUpdateUtilLastStep()))
{
flags |= IModelDelta.CONTENT;
}
if (IDebugUIConstants.ID_REGISTER_VIEW.equals(view_id) ||
IDebugUIConstants.ID_EXPRESSION_VIEW.equals(view_id) ||
TCFModel.ID_EXPRESSION_HOVER.equals(view_id)) {
if (p.getInput() == this) flags |= IModelDelta.CONTENT;
}
if (flags == 0) continue;
p.addDelta(this, flags);
}
}
private void postAllAndParentsChangedDelta() {
postContentChangedDelta();
TCFNode n = this;
while (n instanceof TCFNodeExecContext) {
TCFNodeExecContext e = (TCFNodeExecContext)n;
if (e.delayed_children_list_delta) e.postContentChangedDelta();
e.postStateChangedDelta();
n = n.parent;
}
}
public void postStateChangedDelta() {
for (TCFModelProxy p : model.getModelProxies()) {
if (IDebugUIConstants.ID_DEBUG_VIEW.equals(p.getPresentationContext().getId())) {
p.addDelta(this, IModelDelta.STATE);
}
}
}
private void postModulesChangedDelta() {
for (TCFModelProxy p : model.getModelProxies()) {
if (IDebugUIConstants.ID_MODULE_VIEW.equals(p.getPresentationContext().getId())) {
p.addDelta(this, IModelDelta.CONTENT);
}
}
}
private void postStackChangedDelta() {
for (TCFModelProxy p : model.getModelProxies()) {
if (IDebugUIConstants.ID_DEBUG_VIEW.equals(p.getPresentationContext().getId())) {
p.addDelta(this, IModelDelta.CONTENT);
}
}
}
void onContextAdded(IRunControl.RunControlContext context) {
model.setDebugViewSelection(this, TCFModel.SELECT_ADDED);
children_exec.onContextAdded(context);
}
void onContextChanged(IRunControl.RunControlContext context) {
assert !isDisposed();
full_name.reset();
run_context.reset(context);
symbols_node.reset();
memory_node.reset();
signal_mask.reset();
reset_capabilities.reset();
if (state.isValid()) {
TCFContextState s = state.getData();
if (s == null || s.is_suspended) state.reset();
}
if (min_state.isValid()) {
TCFContextState s = min_state.getData();
if (s == null || s.is_suspended) min_state.reset();
}
children_stack.reset();
children_stack.onSourceMappingChange();
children_regs.reset();
children_exec.onAncestorContextChanged();
for (TCFNodeSymbol s : symbols.values()) s.onMemoryMapChanged();
postAllChangedDelta();
updateTerminal();
}
void onAncestorContextChanged() {
full_name.reset();
}
void onContextAdded(IMemory.MemoryContext context) {
children_exec.onContextAdded(context);
}
void onContextChanged(IMemory.MemoryContext context) {
assert !isDisposed();
clearLookupCaches();
mem_context.reset(context);
for (TCFNodeSymbol s : symbols.values()) s.onMemoryMapChanged();
postAllChangedDelta();
}
void onContextRemoved() {
assert !isDisposed();
resumed_cnt++;
resume_pending = false;
resumed_by_action = false;
dispose();
postContextRemovedDelta();
launch.removeContextActions(id);
}
void onExpressionAddedOrRemoved() {
children_exps.cancel();
children_stack.onExpressionAddedOrRemoved();
}
void onContainerSuspended(boolean func_call) {
assert !isDisposed();
if (run_context.isValid()) {
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && !ctx.hasState()) return;
}
onContextSuspended(null, null, null, func_call);
}
void onContainerResumed() {
assert !isDisposed();
if (run_context.isValid()) {
IRunControl.RunControlContext ctx = run_context.getData();
if (ctx != null && !ctx.hasState()) return;
}
onContextResumed();
}
void onContextSuspended(String pc, String reason, Map<String,Object> params, boolean func_call) {
assert !isDisposed();
if (pc != null) {
TCFContextState s = new TCFContextState();
s.is_suspended = true;
s.suspend_pc = pc;
s.suspend_reason = reason;
s.suspend_params = params;
state.reset(s);
}
else {
state.reset();
}
min_state.reset();
address.reset();
signal_mask.reset();
children_stack.onSuspended(func_call);
children_exps.onSuspended(func_call);
children_hover_exps.onSuspended(func_call);
children_regs.onSuspended(func_call);
if (!func_call) {
children_log_exps.onSuspended();
}
for (TCFNodeSymbol s : symbols.values()) s.onExeStateChange();
if (model.getActiveAction(id) == null) {
boolean update_now = pc != null || resumed_by_action;
resumed_cnt++;
resume_pending = false;
resumed_by_action = false;
if (update_now) {
children_stack.postAllChangedDelta();
postAllAndParentsChangedDelta();
}
else {
final int cnt = resumed_cnt;
Protocol.invokeLater(500, new Runnable() {
public void run() {
if (cnt != resumed_cnt) return;
if (isDisposed()) return;
children_stack.postAllChangedDelta();
postAllAndParentsChangedDelta();
}
});
}
}
}
void onContextResumed() {
assert !isDisposed();
state.reset();
min_state.reset();
if (!resume_pending) {
final int cnt = ++resumed_cnt;
resume_pending = true;
resumed_by_action = model.getActiveAction(id) != null;
if (resumed_by_action) postAllChangedDelta();
Protocol.invokeLater(400, new Runnable() {
public void run() {
if (cnt != resumed_cnt) return;
if (isDisposed()) return;
resume_pending = false;
postAllAndParentsChangedDelta();
model.onContextRunning();
}
});
}
}
void onContextStateChanged() {
assert !isDisposed();
state.reset();
min_state.reset();
postStateChangedDelta();
}
void onContextActionDone() {
if (state.getData() == null || state.getData().is_suspended) {
resumed_cnt++;
resume_pending = false;
resumed_by_action = false;
}
postAllChangedDelta();
children_stack.postAllChangedDelta();
}
void onContextException(String msg) {
}
void onOtherContextSuspended() {
// Other context suspended in same memory space
// Expressions with global variables should be invalidated
children_exps.onMemoryChanged();
children_hover_exps.onMemoryChanged();
children_log_exps.onMemoryChanged();
}
void onMemoryChanged(Number[] addr, long[] size) {
assert !isDisposed();
children_stack.onMemoryChanged();
children_exps.onMemoryChanged();
children_hover_exps.onMemoryChanged();
children_log_exps.onMemoryChanged();
postContentChangedDelta();
}
void onMemoryMapChanged() {
clearLookupCaches();
memory_map.reset();
children_modules.onMemoryMapChanged();
children_stack.onMemoryMapChanged();
children_exps.onMemoryMapChanged();
children_hover_exps.onMemoryMapChanged();
children_log_exps.onMemoryMapChanged();
postContentChangedDelta();
postModulesChangedDelta();
}
void onRegistersChanged() {
children_stack.onRegistersChanged();
children_regs.onRegistersChanged();
postContentChangedDelta();
}
void onRegisterValueChanged() {
if (state.isValid()) {
TCFContextState s = state.getData();
if (s == null || s.is_suspended) state.reset();
}
if (min_state.isValid()) {
TCFContextState s = min_state.getData();
if (s == null || s.is_suspended) min_state.reset();
}
address.reset();
children_stack.onRegisterValueChanged();
children_exps.onRegisterValueChanged();
children_hover_exps.onRegisterValueChanged();
children_log_exps.onRegisterValueChanged();
postContentChangedDelta();
}
void onPreferencesChanged() {
if (delayed_children_list_delta && !model.getDelayChildrenListUpdates() ||
model.getAutoChildrenListUpdates()) postContentChangedDelta();
children_stack.onPreferencesChanged();
postStackChangedDelta();
}
void riseTraceLimit() {
children_stack.riseTraceLimit();
postStackChangedDelta();
}
boolean appendPointedObject(StyledStringBuffer bf, BigInteger addr, Runnable done) {
TCFDataCache<TCFNodeExecContext> mem_node_cache = model.searchMemoryContext(this);
if (mem_node_cache == null) return true;
if (!mem_node_cache.validate(done)) return false;
if (mem_node_cache.getData() == null) return true;
TCFDataCache<TCFFunctionRef> func_info_cache = mem_node_cache.getData().getFuncInfo(addr);
if (func_info_cache == null) return true;
if (!func_info_cache.validate(done)) return false;
TCFFunctionRef func_ref = func_info_cache.getData();
if (func_ref != null && func_ref.symbol_id != null) {
TCFDataCache<ISymbols.Symbol> sym_cache = model.getSymbolInfoCache(func_ref.symbol_id);
if (!sym_cache.validate(done)) return false;
ISymbols.Symbol sym_data = sym_cache.getData();
if (sym_data != null && sym_data.getName() != null) {
bf.append(", ");
bf.append("At: ", SWT.BOLD);
bf.append(sym_data.getName());
if (sym_data.getSymbolClass() == ISymbols.SymbolClass.function) {
bf.append("()");
}
BigInteger func_addr = JSON.toBigInteger(sym_data.getAddress());
if (func_addr != null) {
BigInteger addr_offs = addr.subtract(func_addr);
int cmp = addr_offs.compareTo(BigInteger.ZERO);
if (cmp > 0) {
bf.append(" + 0x" + addr_offs.toString(16));
}
else if (cmp < 0) {
bf.append(" - 0x" + addr_offs.abs().toString(16));
}
}
}
}
return true;
}
public boolean hasSuspendedChildren(ChildrenStateInfo info, Runnable done) {
if (!children_exec.validate(done)) return false;
Map<String,TCFNode> m = children_exec.getData();
if (m == null || m.size() == 0) return true;
for (TCFNode n : m.values()) {
if (!(n instanceof TCFNodeExecContext)) continue;
TCFNodeExecContext e = (TCFNodeExecContext)n;
if (!e.run_context.validate(done)) return false;
IRunControl.RunControlContext ctx = e.run_context.getData();
if (ctx != null && ctx.hasState()) {
TCFDataCache<TCFContextState> state_cache = e.getMinState();
if (!state_cache.validate(done)) return false;
TCFContextState state_data = state_cache.getData();
if (state_data != null) {
if (!state_data.is_suspended) {
info.running = true;
}
else if (state_data.isNotActive()) {
info.not_active = true;
}
else {
info.suspended = true;
String r = model.getContextActionResult(e.id);
if (r == null) r = state_data.suspend_reason;
if (IRunControl.REASON_BREAKPOINT.equals(r)) info.breakpoint = true;
}
}
}
else {
if (!e.hasSuspendedChildren(info, done)) return false;
}
if (info.breakpoint && info.running) break;
}
return true;
}
@Override
public int compareTo(TCFNode n) {
if (n instanceof TCFNodeExecContext) {
TCFNodeExecContext f = (TCFNodeExecContext)n;
if (exe_seq_no < f.exe_seq_no) return -1;
if (exe_seq_no > f.exe_seq_no) return +1;
if (mem_seq_no < f.mem_seq_no) return -1;
if (mem_seq_no > f.mem_seq_no) return +1;
}
return id.compareTo(n.id);
}
}