/*
DisassemblerDecoder.java
(c) 2012-2013 Edward Swartz
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
*/
package v9t9.gui.client.swt.shells.debugger;
import java.util.BitSet;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ITableColorProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import v9t9.common.asm.Block;
import v9t9.common.asm.IDecompilePhase;
import v9t9.common.asm.IHighLevelInstruction;
import v9t9.common.asm.IRawInstructionFactory;
import v9t9.common.asm.RawInstruction;
import v9t9.common.asm.Routine;
import v9t9.common.machine.IMachine;
import v9t9.common.memory.IMemoryDomain;
import v9t9.gui.common.IMemoryDecoder;
/**
* @author ejs
*
*/
public class DisassemblerDecoder implements IMemoryDecoder {
/**
* @author ejs
*
*/
private final class DisassemblerDecoderLabelProvider extends LabelProvider implements ITableColorProvider {
private Color RED = new Color(Display.getDefault(), 255, 0, 0);
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
*/
@Override
public String getText(Object element) {
return ((IDecodedContent) element).getContent().toString();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableColorProvider#getForeground(java.lang.Object, int)
*/
@Override
public Color getForeground(Object element, int columnIndex) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableColorProvider#getBackground(java.lang.Object, int)
*/
@Override
public Color getBackground(Object element, int columnIndex) {
int pc = ((DecodedRow) element).getContent().getAddr();
if (machine.getExecutor().getBreakpoints().findBreakpoint(pc) != null) {
return RED;
}
return null;
}
}
private final int chunkSize;
final IMemoryDomain domain;
private boolean dirty = true;
private int[] indexToAddrMap;
private TreeMap<Integer, IHighLevelInstruction> addrToInstrMap = new TreeMap<Integer, IHighLevelInstruction>();
private final IDecompilePhase decompilePhase;
private IMachine machine;
/**
* @param entry
* @param instructionFactory
*/
public DisassemblerDecoder(IMachine machine,
IMemoryDomain domain, IRawInstructionFactory instructionFactory, IDecompilePhase decompilePhase) {
this.machine = machine;
this.domain = domain;
this.decompilePhase = decompilePhase;
this.chunkSize = instructionFactory.getChunkSize();
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#getLabelProvider()
*/
@Override
public ILabelProvider getLabelProvider() {
return new DisassemblerDecoderLabelProvider();
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#getChunkSize()
*/
@Override
public int getChunkSize() {
return chunkSize;
}
private void refresh() {
if (!dirty)
return;
decompilePhase.disassemble();
decompilePhase.run();
TreeSet<Integer> addrs = new TreeSet<Integer>();
if (true) {
// until the below is more reliable
if (!decompilePhase.getBlocks().isEmpty()) {
Block block = decompilePhase.getBlocks().iterator().next();
IHighLevelInstruction instr = block.getFirst();
while (instr != null) {
addrToInstrMap.put(instr.getInst().getPc(), instr);
addrs.add(instr.getInst().getPc());
instr = instr.getLogicalNext();
}
}
} else {
for (Routine routine : decompilePhase.getRoutines()) {
for (Block block : routine.getSpannedBlocks()) {
IHighLevelInstruction instr = block.getFirst();
while (instr != null) {
addrToInstrMap.put(instr.getInst().getPc(), instr);
addrs.add(instr.getInst().getPc());
if (instr == block.getLast())
break;
instr = instr.getLogicalNext();
}
}
}
}
int idx = 0;
indexToAddrMap = new int[addrs.size()];
for (Integer addr : addrs) {
indexToAddrMap[idx++] = addr;
}
dirty = false;
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#reset()
*/
@Override
public void reset() {
if (decompilePhase == null)
return;
decompilePhase.getDecompileInfo().getMemoryRanges().clear();
decompilePhase.getDecompileInfo().getInstructions().clear();
decompilePhase.reset();
addrToInstrMap.clear();
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#addRange(int, int)
*/
@Override
public void addRange(int addr, int size) {
if (decompilePhase == null)
return;
decompilePhase.getDecompileInfo().getMemoryRanges().
addRange(addr, size, true);
dirty = true;
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#updateRange(java.util.BitSet)
*/
@Override
public void updateRange(BitSet addrSet) {
if (decompilePhase == null)
return;
//decompilePhase.getDecompileInfo().getMemoryRanges().clear();
BitSet workingSet = (BitSet) addrSet.clone();
boolean needsRebuild = false;
Map<Integer, RawInstruction> instructions = decompilePhase.getDecompileInfo().getInstructions();
for (int addr = workingSet.nextSetBit(0); addr >= 0 ; addr = workingSet.nextSetBit(addr + 1)) {
RawInstruction inst = instructions.remove(addr);
needsRebuild = true;
if (inst != null) {
for (int i = 1; i < inst.getSize() + getChunkSize(); i++) {
workingSet.set(addr + i);
}
}
addrToInstrMap.remove(addr);
}
if (needsRebuild) {
addrToInstrMap.clear();
decompilePhase.reset();
}
dirty = true;
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#getItemCount()
*/
@Override
public int getItemCount(int addr, int size) {
refresh();
if (indexToAddrMap == null)
return 0;
int cnt = 0;
for (int a : indexToAddrMap) {
if (a >= addr && a < addr + size)
cnt++;
}
return cnt;
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#getItemCount()
*/
@Override
public int getFirstItemIndex(int addr) {
refresh();
if (indexToAddrMap == null)
return 0;
int cnt = 0;
for (int a : indexToAddrMap) {
if (a >= addr)
return cnt;
cnt++;
}
return cnt;
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#decode(int, int)
*/
@Override
public IDecodedContent decodeItem(int index) {
refresh();
int addr = indexToAddrMap[index];
final IHighLevelInstruction hl = addrToInstrMap.get(addr);
if (hl == null)
throw new IllegalStateException();
final RawInstruction instr = hl.getInst();
return new IDecodedContent() {
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "instr: " + instr;
}
@Override
public int getAddr() {
return instr.getPc();
}
@Override
public int getSize() {
return instr.getSize();
}
@Override
public Object getContent() {
return instr;
}
};
}
/* (non-Javadoc)
* @see v9t9.gui.common.IMemoryDecoder#fillMenu(org.eclipse.swt.widgets.Menu, v9t9.gui.client.swt.shells.debugger.IDecodedContent)
*/
@Override
public void fillMenu(Menu menu, IDecodedContent content) {
final int pc = content.getAddr();
DebuggerWindow.addBreakpointActions(machine, menu, pc);
}
}