Merge remote-tracking branch 'origin/patch'

This commit is contained in:
ghidra1 2022-01-04 19:18:55 -05:00
commit a5e16b7237
10 changed files with 112 additions and 73 deletions

View file

@ -57,7 +57,7 @@
<LI>Address - when evaluation succeeds, the address of the watch's value. This field is
really only meaningful when the outermost operator of the expression is a memory dereference.
Double-clicking a row will navigate the primary dynamic listing to this address, if
Double-clicking this cell will navigate the primary dynamic listing to this address, if
possible.</LI>
<LI>Value - the raw bytes of the watched buffer. If the expression is a register, then this
@ -71,7 +71,9 @@
possible.</LI>
<LI>Representation - the value of the watch as interpreted by the selected data type. This
field is not yet user modifiable, even if the <B>Enable Edits</B> toggle is on.</LI>
field is not yet user modifiable, even if the <B>Enable Edits</B> toggle is on. If the value
is an address, i.e., Type is a pointer, then double-clicking this cell will navigate the
primary dynamic listing, if possible.</LI>
<LI>Error - if an error occurs during compilation or evaluation of the expression, that error
is rendered here. Double-clicking the row will display the stack trace. Note that errors

View file

@ -20,7 +20,6 @@ import java.awt.FontMetrics;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import docking.widgets.fieldpanel.internal.LayoutBackgroundColorManager;
import docking.widgets.fieldpanel.support.FieldSelection;
@ -34,7 +33,6 @@ import ghidra.framework.options.AutoOptions;
import ghidra.framework.options.annotation.AutoOptionConsumed;
import ghidra.program.model.address.*;
import ghidra.trace.model.Trace;
import ghidra.trace.model.TraceAddressSnapRange;
import ghidra.trace.model.memory.TraceMemoryState;
public class DebuggerMemoryByteViewerComponent extends ByteViewerComponent
@ -71,37 +69,45 @@ public class DebuggerMemoryByteViewerComponent extends ByteViewerComponent
}
Trace trace = coordinates.getTrace();
// TODO: Mimic the listing's background, or factor into common
long snap = coordinates.getSnap();
long viewSnap = coordinates.getViewSnap();
// TODO: Span out and cache?
AddressSetView lineAddresses = translator.convertFieldToAddress(lineFieldSel);
// Because UNKNOWN need not be explicitly recorded, compute it by subtracting others
AddressSet unknown = new AddressSet(lineAddresses);
for (AddressRange range : lineAddresses) {
for (Entry<TraceAddressSnapRange, TraceMemoryState> entry : trace.getMemoryManager()
.getStates(snap, range)) {
if (entry.getValue() != TraceMemoryState.UNKNOWN) {
unknown.delete(entry.getKey().getRange());
}
Color color = colorForState(entry.getValue());
if (color == null) {
continue;
}
// NOTE: Only TraceMemoryState.ERROR should reach here
FieldSelection resultFieldSel =
translator.convertAddressToField(entry.getKey().getRange());
if (!resultFieldSel.isEmpty()) {
selections.add(new ColoredFieldSelection(resultFieldSel, color));
}
AddressSet known = new AddressSet();
AddressSet error = new AddressSet();
for (Address addr : lineAddresses.getAddresses(true)) {
TraceMemoryState state =
trace.getMemoryManager().getViewState(viewSnap, addr).getValue();
switch (state) {
case KNOWN:
known.add(addr);
break;
case ERROR:
error.add(addr);
break;
default:
// Don't care
}
}
if (unknownColor == null) {
AddressSet unknown = new AddressSet(lineAddresses);
unknown.delete(known);
unknown.delete(error);
doAddSelections(unknownColor, unknown, translator, selections);
doAddSelections(errorColor, error, translator, selections);
}
protected void doAddSelections(Color color, AddressSetView set,
SelectionTranslator translator, List<ColoredFieldSelection> selections) {
if (color == null) {
return;
}
for (AddressRange unk : unknown) {
FieldSelection resultFieldSel = translator.convertAddressToField(unk);
if (!resultFieldSel.isEmpty()) {
selections.add(new ColoredFieldSelection(resultFieldSel, unknownColor));
for (AddressRange rng : set) {
FieldSelection resultFieldSel = translator.convertAddressToField(rng);
if (resultFieldSel.isEmpty()) {
continue;
}
selections.add(new ColoredFieldSelection(resultFieldSel, color));
}
}
}
@ -133,18 +139,6 @@ public class DebuggerMemoryByteViewerComponent extends ByteViewerComponent
// NOTE: Cursor, being line-by-line, is done via background color model in super
}
protected Color colorForState(TraceMemoryState state) {
switch (state) {
case ERROR:
return errorColor;
case KNOWN:
return null;
case UNKNOWN:
return unknownColor;
}
throw new AssertionError();
}
@Override
protected LayoutBackgroundColorManager getLayoutSelectionMap(BigInteger layoutIndex) {
Color backgroundColor = backgroundColorModel.getBackgroundColor(layoutIndex);

View file

@ -334,24 +334,7 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter {
if (e.getClickCount() != 2 || e.getButton() != MouseEvent.BUTTON1) {
return;
}
if (myActionContext == null) {
return;
}
WatchRow row = myActionContext.getWatchRow();
if (row == null) {
return;
}
Throwable error = row.getError();
if (error != null) {
Msg.showError(this, getComponent(), "Evaluation error",
"Could not evaluate watch", error);
return;
}
Address address = myActionContext.getWatchRow().getAddress();
if (listingService == null || address == null || !address.isMemoryAddress()) {
return;
}
listingService.goTo(address, true);
navigateToSelectedWatch();
}
});
@ -371,6 +354,44 @@ public class DebuggerWatchesProvider extends ComponentProviderAdapter {
super.contextChanged();
}
protected void navigateToSelectedWatch() {
if (myActionContext == null) {
return;
}
WatchRow row = myActionContext.getWatchRow();
if (row == null) {
return;
}
int modelCol = watchTable.convertColumnIndexToModel(watchTable.getSelectedColumn());
Throwable error = row.getError(); // I don't care the selected column for errors
if (error != null) {
Msg.showError(this, getComponent(), "Evaluation error",
"Could not evaluate watch", error);
}
else if (modelCol == WatchTableColumns.ADDRESS.ordinal()) {
Address address = row.getAddress();
if (address != null) {
navigateToAddress(address);
}
}
else if (modelCol == WatchTableColumns.REPR.ordinal()) {
Object val = row.getValueObj();
if (val instanceof Address) {
navigateToAddress((Address) val);
}
}
}
protected void navigateToAddress(Address address) {
if (listingService == null) {
return;
}
if (address.isMemoryAddress()) {
listingService.goTo(address, true);
return;
}
}
protected void createActions() {
actionEnableEdits = DebuggerResources.EnableEditsAction.builder(plugin)
.enabledWhen(c -> current.getTrace() != null)

View file

@ -64,6 +64,7 @@ public class WatchRow {
private byte[] value;
private byte[] prevValue; // Value at previous coordinates
private String valueString;
private Object valueObj;
private Throwable error = null;
public WatchRow(DebuggerWatchesProvider provider, String expression) {
@ -77,6 +78,7 @@ public class WatchRow {
reads = null;
value = null;
valueString = null;
valueObj = null;
}
protected void recompile() {
@ -125,20 +127,29 @@ public class WatchRow {
address = valueWithAddress.getRight();
reads = executorWithAddress.getReads();
valueString = parseAsDataType();
valueObj = parseAsDataTypeObj();
valueString = parseAsDataTypeStr();
}
catch (Exception e) {
error = e;
}
}
protected String parseAsDataType() {
protected String parseAsDataTypeStr() {
if (dataType == null || value == null) {
return "";
}
MemBuffer buffer = new ByteMemBufferImpl(address, value, language.isBigEndian());
return dataType.getRepresentation(buffer, SettingsImpl.NO_SETTINGS, value.length);
}
protected Object parseAsDataTypeObj() {
if (dataType == null || value == null) {
return null;
}
MemBuffer buffer = new ByteMemBufferImpl(address, value, language.isBigEndian());
return dataType.getValue(buffer, SettingsImpl.NO_SETTINGS, value.length);
}
public static class ReadDepsTraceBytesPcodeExecutorState
extends TraceBytesPcodeExecutorState {
@ -299,7 +310,8 @@ public class WatchRow {
public void setDataType(DataType dataType) {
this.typePath = dataType == null ? null : dataType.getPathName();
this.dataType = dataType;
valueString = parseAsDataType();
valueString = parseAsDataTypeStr();
valueObj = parseAsDataTypeObj();
provider.contextChanged();
}
@ -357,6 +369,10 @@ public class WatchRow {
return valueString;
}
public Object getValueObj() {
return valueObj;
}
public boolean isValueEditable() {
return address != null && provider.isEditsEnabled();
}

View file

@ -54,7 +54,7 @@ dependencies {
runtimeOnly "org.slf4j:slf4j-nop:1.7.25"
// use this if you want slf4j log messages sent to log4j
// runtimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:2.17.0"
// runtimeOnly "org.apache.logging.log4j:log4j-slf4j-impl:2.17.1"
compileOnly "junit:junit:4.12"

View file

@ -52,7 +52,7 @@ public class ObjectiveC2_Class implements StructConverter {
AddressSpace space = _state.program.getAddressFactory().getDefaultAddressSpace();
Address addr = space.getAddress(_index);
Symbol symbol = _state.program.getSymbolTable().getPrimarySymbol(addr);
if (symbol.getParentNamespace().getName().equals(SectionNames.SECT_GOT)) {
if (symbol != null && symbol.getParentNamespace().getName().equals(SectionNames.SECT_GOT)) {
return;
}

View file

@ -37,9 +37,15 @@ public class ObjectiveC2_Method extends ObjectiveC_Method {
if (isSmallList) {
int nameOffset = (int)ObjectiveC1_Utilities.readNextIndex(reader, true);
int namePtr = reader.readInt(_index + nameOffset);
long imagebase = state.program.getImageBase().getOffset(); // When we support dyld_shared_cache, this base will likely have to change
name = reader.readAsciiString(imagebase + namePtr);
long namePtr;
if (state.is32bit) {
namePtr = reader.readInt(_index + nameOffset);
}
else {
namePtr = reader.readLong(_index + nameOffset);
}
name = reader.readAsciiString(namePtr);
int typesOffset = (int)ObjectiveC1_Utilities.readNextIndex(reader, true);
types = reader.readAsciiString(_index + 4 + typesOffset);

View file

@ -1,13 +1,13 @@
MODULE FILE LICENSE: lib/cglib-nodep-2.2.jar Apache License 2.0
MODULE FILE LICENSE: lib/guava-19.0.jar Apache License 2.0
MODULE FILE LICENSE: lib/jdom-legacy-1.1.3.jar JDOM License
MODULE FILE LICENSE: lib/log4j-api-2.17.0.jar Apache License 2.0
MODULE FILE LICENSE: lib/log4j-core-2.17.0.jar Apache License 2.0
MODULE FILE LICENSE: lib/log4j-api-2.17.1.jar Apache License 2.0
MODULE FILE LICENSE: lib/log4j-core-2.17.1.jar Apache License 2.0
MODULE FILE LICENSE: lib/commons-collections4-4.1.jar Apache License 2.0
MODULE FILE LICENSE: lib/commons-lang3-3.9.jar Apache License 2.0
MODULE FILE LICENSE: lib/commons-io-2.6.jar Apache License 2.0
MODULE FILE LICENSE: lib/commons-text-1.6.jar Apache License 2.0
MODULE FILE LICENSE: lib/gson-2.8.6.jar Apache License 2.0
MODULE FILE LICENSE: lib/gson-2.8.9.jar Apache License 2.0
MODULE FILE LICENSE: lib/bcpkix-jdk15on-1.69.jar Bouncy Castle License
MODULE FILE LICENSE: lib/bcprov-jdk15on-1.69.jar Bouncy Castle License
MODULE FILE LICENSE: lib/bcutil-jdk15on-1.69.jar Bouncy Castle License

View file

@ -29,13 +29,13 @@ dependencies {
api "cglib:cglib-nodep:2.2"
api "com.google.guava:guava:19.0"
api "org.jdom:jdom-legacy:1.1.3"
api "org.apache.logging.log4j:log4j-api:2.17.0"
api "org.apache.logging.log4j:log4j-core:2.17.0"
api "org.apache.logging.log4j:log4j-api:2.17.1"
api "org.apache.logging.log4j:log4j-core:2.17.1"
api "org.apache.commons:commons-collections4:4.1"
api "org.apache.commons:commons-lang3:3.9"
api "org.apache.commons:commons-text:1.6"
api "commons-io:commons-io:2.6"
api "com.google.code.gson:gson:2.8.6"
api "com.google.code.gson:gson:2.8.9"
api 'org.bouncycastle:bcpkix-jdk15on:1.69' // requires bcutil and bcprov
api 'org.bouncycastle:bcprov-jdk15on:1.69'
api 'org.bouncycastle:bcutil-jdk15on:1.69'

View file

@ -19,7 +19,7 @@ eclipse.project.name = '_JsonDoclet'
apply plugin: 'java-library'
dependencies {
api "com.google.code.gson:gson:2.8.6"
api "com.google.code.gson:gson:2.8.9"
}
rootProject.createJsondocs.dependsOn jar