mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-26 03:46:08 +08:00
Merge remote-tracking branch 'origin/GP-1883_Dan_pcodeStepperLabels--SQUASHED'
This commit is contained in:
+6
-1
@@ -27,10 +27,15 @@ public class BranchPcodeRow implements PcodeRow {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSequence() {
|
||||
public int getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "(branched from " + fromSeq + ")";
|
||||
|
||||
+121
-35
@@ -107,6 +107,7 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
|
||||
protected enum PcodeTableColumns implements EnumeratedTableColumn<PcodeTableColumns, PcodeRow> {
|
||||
SEQUENCE("Sequence", Integer.class, PcodeRow::getSequence),
|
||||
LABEL("Label", String.class, PcodeRow::getLabel),
|
||||
CODE("Code", String.class, PcodeRow::getCode);
|
||||
|
||||
private final String header;
|
||||
@@ -331,90 +332,122 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
class ToPcodeRowsAppender extends AbstractAppender<List<PcodeRow>> {
|
||||
private final List<PcodeRow> rows = new ArrayList<>();
|
||||
private final PcodeFrame frame;
|
||||
private StringBuilder html;
|
||||
|
||||
private boolean hasLabel;
|
||||
private StringBuilder labelHtml;
|
||||
private StringBuilder codeHtml;
|
||||
|
||||
private PcodeOp op;
|
||||
private boolean isNext;
|
||||
|
||||
public ToPcodeRowsAppender(Language language, boolean indent, PcodeFrame frame) {
|
||||
super(language, indent);
|
||||
public ToPcodeRowsAppender(Language language, PcodeFrame frame) {
|
||||
super(language, false);
|
||||
this.frame = frame;
|
||||
}
|
||||
|
||||
void startRow(PcodeOp op, boolean isNext) {
|
||||
if (hasLabel && this.op == null) {
|
||||
// Just continue formatting the current label-only row
|
||||
}
|
||||
else {
|
||||
// Reset and actually start a new row
|
||||
labelHtml = new StringBuilder("<html>");
|
||||
hasLabel = false;
|
||||
codeHtml = new StringBuilder("<html>");
|
||||
}
|
||||
this.op = op;
|
||||
this.isNext = isNext;
|
||||
html = new StringBuilder("<html>");
|
||||
}
|
||||
|
||||
void endRow() {
|
||||
html.append("</html>");
|
||||
rows.add(new OpPcodeRow(language, op, isNext, html.toString()));
|
||||
if (hasLabel && op == null) {
|
||||
// Don't end, just wait for the code
|
||||
}
|
||||
else {
|
||||
// Actually append the row
|
||||
labelHtml.append("</html>");
|
||||
codeHtml.append("</html>");
|
||||
rows.add(new OpPcodeRow(language, op, isNext, labelHtml.toString(),
|
||||
codeHtml.toString()));
|
||||
hasLabel = false;
|
||||
op = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendAddressWordOffcut(long wordOffset, long offcut) {
|
||||
html.append(htmlSpan(SPAN_ADDRESS, stringifyWordOffcut(wordOffset, offcut)));
|
||||
codeHtml.append(htmlSpan(SPAN_ADDRESS, stringifyWordOffcut(wordOffset, offcut)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendCharacter(char c) {
|
||||
if (c == '=') {
|
||||
html.append(htmlSpan(SPAN_SEPARATOR, " = "));
|
||||
codeHtml.append(" ");
|
||||
codeHtml.append(htmlSpan(SPAN_SEPARATOR, "="));
|
||||
codeHtml.append(" ");
|
||||
}
|
||||
else if (c == ' ') {
|
||||
codeHtml.append(" ");
|
||||
}
|
||||
else {
|
||||
html.append(htmlSpan(SPAN_SEPARATOR, Character.toString(c)));
|
||||
codeHtml.append(htmlSpan(SPAN_SEPARATOR, Character.toString(c)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendIndent() {
|
||||
html.append(" ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendLabel(String label) {
|
||||
html.append(htmlSpan(SPAN_LOCAL, label));
|
||||
codeHtml.append(htmlSpan(SPAN_LOCAL, label));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendLineLabel(long label) {
|
||||
hasLabel = true;
|
||||
labelHtml.append(htmlSpan(SPAN_LINE_LABEL, stringifyLineLabel(label)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendLineLabelRef(long label) {
|
||||
html.append(htmlSpan(SPAN_LINE_LABEL, stringifyLineLabel(label)));
|
||||
codeHtml.append(htmlSpan(SPAN_LINE_LABEL, stringifyLineLabel(label)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendMnemonic(int opcode) {
|
||||
String style = opcode == PcodeOp.UNIMPLEMENTED ? SPAN_UNIMPL : SPAN_MNEMONIC;
|
||||
html.append(htmlSpan(style, stringifyOpMnemonic(opcode)));
|
||||
codeHtml.append(htmlSpan(style, stringifyOpMnemonic(opcode)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendRawVarnode(AddressSpace space, long offset, long size) {
|
||||
html.append(htmlSpan(SPAN_RAW, stringifyRawVarnode(space, offset, size)));
|
||||
codeHtml.append(htmlSpan(SPAN_RAW, stringifyRawVarnode(space, offset, size)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendRegister(Register register) {
|
||||
html.append(htmlSpan(SPAN_REGISTER, stringifyRegister(register)));
|
||||
codeHtml.append(htmlSpan(SPAN_REGISTER, stringifyRegister(register)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendScalar(long value) {
|
||||
html.append(htmlSpan(SPAN_SCALAR, stringifyScalarValue(value)));
|
||||
codeHtml.append(htmlSpan(SPAN_SCALAR, stringifyScalarValue(value)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendSpace(AddressSpace space) {
|
||||
html.append(htmlSpan(SPAN_SPACE, stringifySpace(space)));
|
||||
codeHtml.append(htmlSpan(SPAN_SPACE, stringifySpace(space)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendUnique(long offset) {
|
||||
html.append(htmlSpan(SPAN_LOCAL, stringifyUnique(offset)));
|
||||
codeHtml.append(htmlSpan(SPAN_LOCAL, stringifyUnique(offset)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendUserop(int id) {
|
||||
html.append(htmlSpan(SPAN_USEROP, stringifyUserop(language, id)));
|
||||
codeHtml.append(htmlSpan(SPAN_USEROP, stringifyUserop(language, id)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -428,6 +461,15 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
|
||||
@Override
|
||||
public List<PcodeRow> finish() {
|
||||
String label;
|
||||
if (hasLabel) {
|
||||
labelHtml.append("</html>");
|
||||
label = labelHtml.toString();
|
||||
}
|
||||
else {
|
||||
label = "";
|
||||
}
|
||||
rows.add(new FallthroughPcodeRow(frame.getCode().size(), frame.isFallThrough(), label));
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
@@ -451,7 +493,7 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
|
||||
@Override
|
||||
protected ToPcodeRowsAppender createAppender(Language language, boolean indent) {
|
||||
return new ToPcodeRowsAppender(language, indent, frame);
|
||||
return new ToPcodeRowsAppender(language, frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -541,6 +583,7 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
PcodeTableModel pcodeTableModel = new PcodeTableModel();
|
||||
JLabel instructionLabel;
|
||||
// No filter panel on p-code
|
||||
PcodeCellRenderer codeColRenderer;
|
||||
|
||||
DockingAction actionStepBackward;
|
||||
DockingAction actionStepForward;
|
||||
@@ -696,16 +739,31 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
pcodeTableModel.fireTableDataChanged();
|
||||
}
|
||||
|
||||
protected int computeSeqColWidth(JLabel renderer) {
|
||||
protected int measureColWidth(JLabel renderer, String sample) {
|
||||
Font font = renderer.getFont();
|
||||
Insets insets = renderer.getBorder().getBorderInsets(renderer);
|
||||
return (int) font.getStringBounds("00", METRIC_FRC).getWidth() + insets.left + insets.right;
|
||||
return (int) font.getStringBounds(sample, METRIC_FRC).getWidth() + insets.left +
|
||||
insets.right;
|
||||
}
|
||||
|
||||
protected int measureWidthHtml(JLabel renderer, String sampleHtml) {
|
||||
String sampleText = HTMLUtilities.fromHTML(sampleHtml);
|
||||
return measureColWidth(renderer, sampleText);
|
||||
}
|
||||
|
||||
protected void buildMainPanel() {
|
||||
JPanel pcodePanel = new JPanel(new BorderLayout());
|
||||
// An intervening panel to interrupt swings table-viewport nonsense
|
||||
// This will allow the viewport to properly fit the table's contents
|
||||
JPanel pcodeTablePanel = new JPanel(new BorderLayout());
|
||||
pcodeTable = new GhidraTable(pcodeTableModel);
|
||||
pcodePanel.add(new JScrollPane(pcodeTable));
|
||||
pcodeTablePanel.add(pcodeTable, BorderLayout.CENTER);
|
||||
|
||||
JScrollPane pcodeScrollPane = new JScrollPane(pcodeTablePanel,
|
||||
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
|
||||
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
|
||||
JPanel pcodePanel = new JPanel(new BorderLayout());
|
||||
pcodePanel.add(pcodeScrollPane, BorderLayout.CENTER);
|
||||
instructionLabel = new JLabel();
|
||||
pcodePanel.add(instructionLabel, BorderLayout.NORTH);
|
||||
mainPanel.setLeftComponent(pcodePanel);
|
||||
@@ -732,12 +790,17 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
TableColumn seqCol = pcodeColModel.getColumn(PcodeTableColumns.SEQUENCE.ordinal());
|
||||
CounterBackgroundCellRenderer seqColRenderer = new CounterBackgroundCellRenderer();
|
||||
seqCol.setCellRenderer(seqColRenderer);
|
||||
int seqColWidth = computeSeqColWidth(seqColRenderer);
|
||||
int seqColWidth = measureColWidth(seqColRenderer, "00");
|
||||
seqCol.setMinWidth(seqColWidth);
|
||||
seqCol.setMaxWidth(seqColWidth);
|
||||
TableColumn labelCol = pcodeColModel.getColumn(PcodeTableColumns.LABEL.ordinal());
|
||||
codeColRenderer = new PcodeCellRenderer();
|
||||
labelCol.setCellRenderer(codeColRenderer);
|
||||
int labelColWidth = measureColWidth(codeColRenderer, "<00>");
|
||||
labelCol.setMinWidth(labelColWidth);
|
||||
labelCol.setMaxWidth(labelColWidth);
|
||||
TableColumn codeCol = pcodeColModel.getColumn(PcodeTableColumns.CODE.ordinal());
|
||||
codeCol.setCellRenderer(new PcodeCellRenderer());
|
||||
//codeCol.setPreferredWidth(75);
|
||||
codeCol.setCellRenderer(codeColRenderer);
|
||||
|
||||
TableColumnModel uniqueColModel = uniqueTable.getColumnModel();
|
||||
TableColumn refCol = uniqueColModel.getColumn(UniqueTableColumns.REF.ordinal());
|
||||
@@ -811,9 +874,7 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
}
|
||||
|
||||
protected void populateSingleton(PcodeRow row) {
|
||||
pcodeTableModel.clear();
|
||||
pcodeTableModel.add(row);
|
||||
uniqueTableModel.clear();
|
||||
}
|
||||
|
||||
protected void populateFromFrame(PcodeFrame frame, PcodeExecutorState<byte[]> state) {
|
||||
@@ -821,22 +882,37 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
populateUnique(frame, state);
|
||||
}
|
||||
|
||||
protected int computeCodeColWidth(List<PcodeRow> rows) {
|
||||
return rows.stream()
|
||||
.map(r -> measureWidthHtml(codeColRenderer, r.getCode()))
|
||||
.reduce(0, Integer::max);
|
||||
}
|
||||
|
||||
protected void adjustCodeColWidth(List<PcodeRow> rows) {
|
||||
TableColumn codeCol =
|
||||
pcodeTable.getColumnModel().getColumn(PcodeTableColumns.CODE.ordinal());
|
||||
int width = computeCodeColWidth(rows);
|
||||
codeCol.setMinWidth(width);
|
||||
codeCol.setPreferredWidth(width);
|
||||
}
|
||||
|
||||
protected void populatePcode(PcodeFrame frame) {
|
||||
Language language = current.getTrace().getBaseLanguage();
|
||||
|
||||
PcodeRowHtmlFormatter formatter = new PcodeRowHtmlFormatter(language, frame);
|
||||
List<PcodeRow> toAdd = formatter.getRows();
|
||||
|
||||
int sel = formatter.nextRowIndex;
|
||||
if (frame.isBranch()) {
|
||||
toAdd.add(new BranchPcodeRow(frame.getCode().size(), frame.getBranched()));
|
||||
sel = frame.getCode().size() + 1;
|
||||
toAdd.add(new BranchPcodeRow(sel, frame.getBranched()));
|
||||
}
|
||||
else if (frame.isFallThrough()) {
|
||||
toAdd.add(new FallthroughPcodeRow(frame.getCode().size()));
|
||||
sel = frame.getCode().size();
|
||||
}
|
||||
pcodeTableModel.clear();
|
||||
adjustCodeColWidth(toAdd);
|
||||
pcodeTableModel.addAll(toAdd);
|
||||
pcodeTable.getSelectionModel()
|
||||
.setSelectionInterval(formatter.nextRowIndex, formatter.nextRowIndex);
|
||||
pcodeTable.getSelectionModel().setSelectionInterval(sel, sel);
|
||||
pcodeTable.scrollToSelectedRow();
|
||||
}
|
||||
|
||||
@@ -862,37 +938,47 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||
uniques.stream()
|
||||
.map(u -> new UniqueRow(this, language, state, u))
|
||||
.collect(Collectors.toList());
|
||||
uniqueTableModel.clear();
|
||||
uniqueTableModel.addAll(toAdd);
|
||||
}
|
||||
|
||||
protected void clear() {
|
||||
pcodeTableModel.clear();
|
||||
uniqueTableModel.clear();
|
||||
}
|
||||
|
||||
protected void doLoadPcodeFrame() {
|
||||
if (instructionLabel != null) {
|
||||
instructionLabel.setText("(no instruction)");
|
||||
}
|
||||
if (emulationService == null) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
DebuggerCoordinates current = this.current; // Volatile, also after background
|
||||
Trace trace = current.getTrace();
|
||||
if (trace == null) {
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
if (current.getThread() == null) {
|
||||
clear();
|
||||
populateSingleton(EnumPcodeRow.NO_THREAD);
|
||||
return;
|
||||
}
|
||||
TraceSchedule time = current.getTime();
|
||||
if (time.pTickCount() == 0) {
|
||||
clear();
|
||||
populateSingleton(EnumPcodeRow.DECODE);
|
||||
return;
|
||||
}
|
||||
DebuggerTracePcodeEmulator emu = emulationService.getCachedEmulator(trace, time);
|
||||
if (emu != null) {
|
||||
clear();
|
||||
doLoadPcodeFrameFromEmulator(emu);
|
||||
return;
|
||||
}
|
||||
emulationService.backgroundEmulate(trace, time).thenAcceptAsync(__ -> {
|
||||
clear();
|
||||
if (current != this.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
+6
-1
@@ -27,10 +27,15 @@ public enum EnumPcodeRow implements PcodeRow {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSequence() {
|
||||
public int getSequence() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return message;
|
||||
|
||||
+12
-3
@@ -19,16 +19,25 @@ import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
public class FallthroughPcodeRow implements PcodeRow {
|
||||
private final int sequence;
|
||||
private final boolean isNext;
|
||||
private final String label;
|
||||
|
||||
public FallthroughPcodeRow(int sequence) {
|
||||
public FallthroughPcodeRow(int sequence, boolean isNext, String label) {
|
||||
this.sequence = sequence;
|
||||
this.isNext = isNext;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSequence() {
|
||||
public int getSequence() {
|
||||
return sequence;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return "(fall-through)";
|
||||
@@ -36,7 +45,7 @@ public class FallthroughPcodeRow implements PcodeRow {
|
||||
|
||||
@Override
|
||||
public boolean isNext() {
|
||||
return true;
|
||||
return isNext;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+12
-6
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package ghidra.app.plugin.core.debug.gui.pcode;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
@@ -22,23 +24,27 @@ public class OpPcodeRow implements PcodeRow {
|
||||
protected final Language language;
|
||||
protected final PcodeOp op;
|
||||
protected final boolean isNext;
|
||||
protected final String label;
|
||||
protected final String code;
|
||||
|
||||
public OpPcodeRow(Language language, PcodeOp op, boolean isNext, String code) {
|
||||
public OpPcodeRow(Language language, PcodeOp op, boolean isNext, String label, String code) {
|
||||
this.language = language;
|
||||
this.op = op;
|
||||
this.op = Objects.requireNonNull(op);
|
||||
this.isNext = isNext;
|
||||
this.label = label;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getSequence() {
|
||||
if (op == null) {
|
||||
return null;
|
||||
}
|
||||
public int getSequence() {
|
||||
return op.getSeqnum().getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return code;
|
||||
|
||||
+3
-1
@@ -18,7 +18,9 @@ package ghidra.app.plugin.core.debug.gui.pcode;
|
||||
import ghidra.program.model.pcode.PcodeOp;
|
||||
|
||||
public interface PcodeRow {
|
||||
Integer getSequence();
|
||||
int getSequence();
|
||||
|
||||
String getLabel();
|
||||
|
||||
String getCode();
|
||||
|
||||
|
||||
+125
-7
@@ -17,6 +17,8 @@ package ghidra.app.plugin.core.debug.gui.pcode;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -26,12 +28,14 @@ import ghidra.app.plugin.assembler.Assembler;
|
||||
import ghidra.app.plugin.assembler.Assemblers;
|
||||
import ghidra.app.plugin.core.debug.gui.AbstractGhidraHeadedDebuggerGUITest;
|
||||
import ghidra.app.plugin.core.debug.gui.listing.DebuggerListingPlugin;
|
||||
import ghidra.app.plugin.core.debug.gui.pcode.DebuggerPcodeStepperProvider.PcodeRowHtmlFormatter;
|
||||
import ghidra.app.plugin.core.debug.service.emulation.DebuggerTracePcodeEmulator;
|
||||
import ghidra.app.plugin.core.debug.service.tracemgr.DebuggerTraceManagerServicePlugin;
|
||||
import ghidra.app.plugin.processors.sleigh.SleighLanguage;
|
||||
import ghidra.app.services.DebuggerEmulationService;
|
||||
import ghidra.app.services.DebuggerTraceManagerService;
|
||||
import ghidra.pcode.emu.PcodeThread;
|
||||
import ghidra.pcode.exec.PcodeExecutor;
|
||||
import ghidra.pcode.exec.*;
|
||||
import ghidra.pcode.exec.trace.TraceSleighUtils;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Instruction;
|
||||
@@ -50,6 +54,11 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||
protected DebuggerPcodeStepperProvider pcodeProvider;
|
||||
protected DebuggerEmulationService emuService;
|
||||
|
||||
private Address start;
|
||||
private TraceThread thread;
|
||||
private Instruction imm1234;
|
||||
private Instruction imm2045;
|
||||
|
||||
@Before
|
||||
public void setUpPcodeStepperProviderTest() throws Exception {
|
||||
traceManager = addPlugin(tool, DebuggerTraceManagerServicePlugin.class);
|
||||
@@ -62,10 +71,8 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||
createTrace();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomUseropDisplay() throws Exception {
|
||||
Address start = tb.addr(0x00400000);
|
||||
TraceThread thread;
|
||||
protected void populateTrace() throws Exception {
|
||||
start = tb.addr(0x00400000);
|
||||
InstructionIterator iit;
|
||||
try (UndoableTransaction tid = tb.startTransaction()) {
|
||||
tb.trace.getMemoryManager()
|
||||
@@ -83,8 +90,45 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||
"imm r1, #2045"); // 11 bits unsigned
|
||||
|
||||
}
|
||||
Instruction imm1234 = iit.next();
|
||||
Instruction imm2045 = iit.next();
|
||||
imm1234 = iit.next();
|
||||
imm2045 = iit.next();
|
||||
}
|
||||
|
||||
protected void assertEmpty() {
|
||||
assertTrue(pcodeProvider.pcodeTableModel.getModelData().isEmpty());
|
||||
assertTrue(pcodeProvider.uniqueTableModel.getModelData().isEmpty());
|
||||
}
|
||||
|
||||
protected void assertPopulated() {
|
||||
assertFalse(pcodeProvider.pcodeTableModel.getModelData().isEmpty());
|
||||
// NB. I don't know what uniques, if any, are involved
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() throws Exception {
|
||||
assertEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloseCurrentTraceEmpty() throws Exception {
|
||||
populateTrace();
|
||||
|
||||
TraceSchedule schedule1 = TraceSchedule.parse("0:.t0-1");
|
||||
traceManager.openTrace(tb.trace);
|
||||
traceManager.activateThread(thread);
|
||||
assertEmpty();
|
||||
|
||||
traceManager.activateTime(schedule1);
|
||||
waitForPass(() -> assertEquals(schedule1, pcodeProvider.current.getTime()));
|
||||
waitForPass(() -> assertPopulated());
|
||||
|
||||
traceManager.closeTrace(tb.trace);
|
||||
waitForPass(() -> assertEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomUseropDisplay() throws Exception {
|
||||
populateTrace();
|
||||
|
||||
TraceSchedule schedule1 = TraceSchedule.parse("0:.t0-1");
|
||||
traceManager.openTrace(tb.trace);
|
||||
@@ -121,4 +165,78 @@ public class DebuggerPcodeStepperProviderTest extends AbstractGhidraHeadedDebugg
|
||||
.stream()
|
||||
.anyMatch(r -> r.getCode().contains("emu_swi"))));
|
||||
}
|
||||
|
||||
protected List<PcodeRow> format(List<String> sleigh) {
|
||||
SleighLanguage language = (SleighLanguage) getToyBE64Language();
|
||||
PcodeProgram prog = SleighProgramCompiler.compileProgram(language, "test", sleigh,
|
||||
SleighUseropLibrary.nil());
|
||||
PcodeExecutor<byte[]> executor =
|
||||
new PcodeExecutor<>(language, PcodeArithmetic.BYTES_BE, null);
|
||||
PcodeFrame frame = executor.begin(prog);
|
||||
PcodeRowHtmlFormatter formatter = pcodeProvider.new PcodeRowHtmlFormatter(language, frame);
|
||||
return formatter.getRows();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPcodeFormatterSimple() {
|
||||
List<PcodeRow> rows = format(List.of("r0 = 1;"));
|
||||
assertEquals(2, rows.size());
|
||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||
assertEquals(FallthroughPcodeRow.class, rows.get(1).getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPcodeFormatterStartsLabel() {
|
||||
List<PcodeRow> rows = format(List.of(
|
||||
"<L0> r0 = 1;",
|
||||
"goto <L0>;"));
|
||||
assertEquals(3, rows.size());
|
||||
assertEquals("<html><span class=\"lab\"><0></span></html>", rows.get(0).getLabel());
|
||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||
assertEquals(FallthroughPcodeRow.class, rows.get(2).getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPcodeFormatterMiddleLabel() {
|
||||
List<PcodeRow> rows = format(List.of(
|
||||
"if 1:1 goto <SKIP>;",
|
||||
"r0 = 1;",
|
||||
"<SKIP> r1 = 2;"));
|
||||
assertEquals(4, rows.size());
|
||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||
assertEquals("<html><span class=\"lab\"><0></span></html>", rows.get(2).getLabel());
|
||||
assertEquals(FallthroughPcodeRow.class, rows.get(3).getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPcodeFormatterFallthroughLabel() {
|
||||
List<PcodeRow> rows = format(List.of(
|
||||
"if 1:1 goto <SKIP>;",
|
||||
"r0 = 1;",
|
||||
"<SKIP>"));
|
||||
assertEquals(3, rows.size());
|
||||
assertEquals("<html></html>", rows.get(0).getLabel());
|
||||
assertEquals("<html></html>", rows.get(1).getLabel());
|
||||
assertEquals("<html><span class=\"lab\"><0></span></html>", rows.get(2).getLabel());
|
||||
assertEquals(FallthroughPcodeRow.class, rows.get(2).getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPcodeFormatterManyLabel() {
|
||||
List<PcodeRow> rows = format(List.of(
|
||||
"<L0> goto <L1>;",
|
||||
"<L1> goto <L2>;",
|
||||
"<L2> goto <L3>;",
|
||||
"goto <L0>;",
|
||||
"<L3>"));
|
||||
assertEquals(5, rows.size());
|
||||
// NB. templates number labels in order of appearance in BRANCHes
|
||||
assertEquals("<html><span class=\"lab\"><3></span></html>", rows.get(0).getLabel());
|
||||
assertEquals("<html><span class=\"lab\"><0></span></html>", rows.get(1).getLabel());
|
||||
assertEquals("<html><span class=\"lab\"><1></span></html>", rows.get(2).getLabel());
|
||||
assertEquals("<html></html>", rows.get(3).getLabel());
|
||||
assertEquals("<html><span class=\"lab\"><2></span></html>", rows.get(4).getLabel());
|
||||
assertEquals(FallthroughPcodeRow.class, rows.get(4).getClass());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user