Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz 2022-03-22 01:49:11 -04:00
commit aa333c1d2f
8 changed files with 154 additions and 98 deletions

View file

@ -65,17 +65,20 @@ public class ObjectiveC2_Method extends ObjectiveC_Method {
public String getName() { public String getName() {
return name; return name;
} }
@Override @Override
public String getTypes() { public String getTypes() {
return types; return types;
} }
@Override @Override
public long getImplementation() { public long getImplementation() {
return imp.getImplementation(); return imp.getImplementation();
} }
@Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
Structure struct = new StructureDataType("method_t", 0); Structure struct = new StructureDataType("method" + (isSmall ? "_small" : "") + "_t", 0);
if (isSmall) { if (isSmall) {
DataType sdw = SignedDWordDataType.dataType; DataType sdw = SignedDWordDataType.dataType;
String comment = "offset from this address"; String comment = "offset from this address";

View file

@ -29,7 +29,8 @@ public class ObjectiveC2_MethodList extends ObjectiveC_MethodList {
private int entsizeAndFlags; private int entsizeAndFlags;
private int count; private int count;
public ObjectiveC2_MethodList(ObjectiveC2_State state, BinaryReader reader, ObjectiveC_MethodType methodType) throws IOException { public ObjectiveC2_MethodList(ObjectiveC2_State state, BinaryReader reader,
ObjectiveC_MethodType methodType) throws IOException {
super(state, reader, NAME); super(state, reader, NAME);
if (_index == 0) { if (_index == 0) {
@ -39,13 +40,17 @@ public class ObjectiveC2_MethodList extends ObjectiveC_MethodList {
entsizeAndFlags = reader.readNextInt(); entsizeAndFlags = reader.readNextInt();
count = reader.readNextInt(); count = reader.readNextInt();
boolean isSmallList = (entsizeAndFlags & 0x80000000) != 0; boolean isSmallList = isSmallMethods();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
methods.add(new ObjectiveC2_Method(state, reader, methodType, isSmallList)); methods.add(new ObjectiveC2_Method(state, reader, methodType, isSmallList));
} }
} }
protected boolean isSmallMethods() {
return (entsizeAndFlags & 0x80000000) != 0;
}
public long getEntsizeAndFlags() { public long getEntsizeAndFlags() {
return entsizeAndFlags; return entsizeAndFlags;
} }
@ -62,8 +67,10 @@ public class ObjectiveC2_MethodList extends ObjectiveC_MethodList {
return struct; return struct;
} }
@Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
Structure struct = new StructureDataType(NAME+'_'+count+'_', 0); Structure struct =
new StructureDataType(NAME + (isSmallMethods() ? "_small" : "") + '_' + count + '_', 0);
struct.add(DWORD, "entsizeAndFlags", null); struct.add(DWORD, "entsizeAndFlags", null);
struct.add(DWORD, "count", null); struct.add(DWORD, "count", null);

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,14 +15,16 @@
*/ */
package ghidra.app.util.bin.format.objectiveC; package ghidra.app.util.bin.format.objectiveC;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
import java.io.IOException;
public class ObjectiveC1_Module implements StructConverter { public class ObjectiveC1_Module implements StructConverter {
private ObjectiveC1_State _state; private ObjectiveC1_State _state;
private long _index; private long _index;
@ -74,9 +75,11 @@ public class ObjectiveC1_Module implements StructConverter {
_state.program.getAddressFactory().getDefaultAddressSpace().getAddress(_index); _state.program.getAddressFactory().getDefaultAddressSpace().getAddress(_index);
DataType dt = toDataType(); DataType dt = toDataType();
try { try {
_state.program.getListing().createData(address, dt); DataUtilities.createData(_state.program, address, dt, -1, false,
ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
} }
catch (Exception e) { catch (Exception e) {
Msg.warn(this, "Could not create " + dt.getName() + " @" + address);
} }
if (symbolTable != null) { if (symbolTable != null) {
@ -84,6 +87,7 @@ public class ObjectiveC1_Module implements StructConverter {
} }
} }
@Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType("objc_module", 0); StructureDataType struct = new StructureDataType("objc_module", 0);
struct.setCategoryPath(ObjectiveC1_Constants.CATEGORY_PATH); struct.setCategoryPath(ObjectiveC1_Constants.CATEGORY_PATH);

View file

@ -23,6 +23,8 @@ import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException; import ghidra.util.exception.DuplicateNameException;
public class ObjectiveC1_SymbolTable implements StructConverter { public class ObjectiveC1_SymbolTable implements StructConverter {
@ -67,12 +69,15 @@ public class ObjectiveC1_SymbolTable implements StructConverter {
public int getSelectorReferenceCount() { public int getSelectorReferenceCount() {
return sel_ref_cnt; return sel_ref_cnt;
} }
public int getRefs() { public int getRefs() {
return refs; return refs;
} }
public short getClassDefinitionCount() { public short getClassDefinitionCount() {
return cls_def_cnt; return cls_def_cnt;
} }
public short getCategoryDefinitionCount() { public short getCategoryDefinitionCount() {
return cat_def_cnt; return cat_def_cnt;
} }
@ -80,6 +85,7 @@ public class ObjectiveC1_SymbolTable implements StructConverter {
public List<ObjectiveC1_Class> getClasses() { public List<ObjectiveC1_Class> getClasses() {
return classes; return classes;
} }
public List<ObjectiveC1_Category> getCategories() { public List<ObjectiveC1_Category> getCategories() {
return categories; return categories;
} }
@ -94,18 +100,23 @@ public class ObjectiveC1_SymbolTable implements StructConverter {
return struct; return struct;
} }
@Override
public DataType toDataType() throws DuplicateNameException, IOException { public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct = new StructureDataType(NAME+"_"+cls_def_cnt+"_"+cat_def_cnt+"_", 0); StructureDataType struct =
new StructureDataType(NAME + "_" + cls_def_cnt + "_" + cat_def_cnt + "_", 0);
struct.setCategoryPath(ObjectiveC1_Constants.CATEGORY_PATH); struct.setCategoryPath(ObjectiveC1_Constants.CATEGORY_PATH);
struct.add(DWORD, "sel_ref_cnt", null); struct.add(DWORD, "sel_ref_cnt", null);
struct.add(DWORD, "refs", null); struct.add(DWORD, "refs", null);
struct.add(WORD, "cls_def_cnt", null); struct.add(WORD, "cls_def_cnt", null);
struct.add(WORD, "cat_def_cnt", null); struct.add(WORD, "cat_def_cnt", null);
for (int i = 0; i < cls_def_cnt; ++i) { for (int i = 0; i < cls_def_cnt; ++i) {
struct.add(PointerDataType.getPointer(classes.get(i).toDataType(), _state.pointerSize), "class"+i, null); struct.add(PointerDataType.getPointer(classes.get(i).toDataType(), _state.pointerSize),
"class" + i, null);
} }
for (int i = 0; i < cat_def_cnt; ++i) { for (int i = 0; i < cat_def_cnt; ++i) {
struct.add(PointerDataType.getPointer(categories.get(i).toDataType(), _state.pointerSize), "category"+i, null); struct.add(
PointerDataType.getPointer(categories.get(i).toDataType(), _state.pointerSize),
"category" + i, null);
} }
return struct; return struct;
} }
@ -116,11 +127,16 @@ public class ObjectiveC1_SymbolTable implements StructConverter {
} }
_state.beenApplied.add(_index); _state.beenApplied.add(_index);
Address address = _state.program.getAddressFactory().getDefaultAddressSpace().getAddress(_index); Address address =
_state.program.getAddressFactory().getDefaultAddressSpace().getAddress(_index);
DataType dt = toDataType();
try { try {
_state.program.getListing().createData(address, toDataType()); DataUtilities.createData(_state.program, address, dt, -1, false,
ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
}
catch (Exception e) {
Msg.warn(this, "Could not create " + dt.getName() + " @" + address);
} }
catch (Exception e) {}
_state.program.getListing().getDefinedDataAt(address); _state.program.getListing().getDefinedDataAt(address);

View file

@ -31,6 +31,7 @@ import ghidra.framework.cmd.Command;
import ghidra.program.database.symbol.ClassSymbol; import ghidra.program.database.symbol.ClassSymbol;
import ghidra.program.model.address.*; import ghidra.program.model.address.*;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.lang.Processor; import ghidra.program.model.lang.Processor;
import ghidra.program.model.lang.Register; import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
@ -48,8 +49,8 @@ public final class ObjectiveC1_Utilities {
* Clears the code units defined in the given memory block. * Clears the code units defined in the given memory block.
*/ */
public static void clear(ObjectiveC2_State state, MemoryBlock block) throws Exception { public static void clear(ObjectiveC2_State state, MemoryBlock block) throws Exception {
state.program.getListing().clearCodeUnits(block.getStart(), block.getEnd(), false, state.program.getListing()
state.monitor); .clearCodeUnits(block.getStart(), block.getEnd(), false, state.monitor);
} }
/** /**
@ -143,9 +144,11 @@ public final class ObjectiveC1_Utilities {
if (data != null && data.getDataType().isEquivalent(dt)) { if (data != null && data.getDataType().isEquivalent(dt)) {
return; return;
} }
//program.getListing().clearCodeUnits(address, address.add(dt.getLength()-1));
program.getListing().createData(address, dt); // need to clear, as pointers could have been created on import
// from following pointer chains
DataUtilities.createData(program, address, dt, -1, false,
ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA);
} }
/** /**
@ -230,8 +233,8 @@ public final class ObjectiveC1_Utilities {
*/ */
public static Symbol createSymbol(Program program, Namespace parentNamespace, String symbolName, public static Symbol createSymbol(Program program, Namespace parentNamespace, String symbolName,
Address symbolAddress) throws InvalidInputException { Address symbolAddress) throws InvalidInputException {
Symbol symbol = program.getSymbolTable().createLabel(symbolAddress, symbolName, Symbol symbol = program.getSymbolTable()
parentNamespace, SourceType.IMPORTED); .createLabel(symbolAddress, symbolName, parentNamespace, SourceType.IMPORTED);
symbol.setPrimary(); symbol.setPrimary();
return symbol; return symbol;
} }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,13 +15,15 @@
*/ */
package ghidra.app.util.bin.format.objectiveC; package ghidra.app.util.bin.format.objectiveC;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverter; import ghidra.app.util.bin.StructConverter;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.DataType;
import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Namespace;
import ghidra.util.Msg;
import java.util.ArrayList;
import java.util.List;
public abstract class ObjectiveC_MethodList implements StructConverter { public abstract class ObjectiveC_MethodList implements StructConverter {
private String _className; private String _className;
@ -31,7 +32,8 @@ public abstract class ObjectiveC_MethodList implements StructConverter {
protected List<ObjectiveC_Method> methods = new ArrayList<ObjectiveC_Method>(); protected List<ObjectiveC_Method> methods = new ArrayList<ObjectiveC_Method>();
protected ObjectiveC_MethodList(ObjectiveC1_State state, BinaryReader reader, String className) { protected ObjectiveC_MethodList(ObjectiveC1_State state, BinaryReader reader,
String className) {
this._state = state; this._state = state;
this._index = reader.getPointerIndex(); this._index = reader.getPointerIndex();
this._className = className; this._className = className;
@ -51,17 +53,23 @@ public abstract class ObjectiveC_MethodList implements StructConverter {
_state.beenApplied.add(_index); _state.beenApplied.add(_index);
Address address = ObjectiveC1_Utilities.toAddress(_state.program, _index); Address address = ObjectiveC1_Utilities.toAddress(_state.program, _index);
DataType dt = toDataType();
try { try {
ObjectiveC1_Utilities.applyData(_state.program, toDataType(), address); ObjectiveC1_Utilities.applyData(_state.program, dt, address);
}
catch (Exception e) {
Msg.warn(this, "Could not create " + dt.getName() + " @" + address);
} }
catch (Exception e) {}
try { try {
//creates a symbol on the method list data structure //creates a symbol on the method list data structure
Namespace methodListNamespace = ObjectiveC1_Utilities.createNamespace(_state.program, ObjectiveC1_Constants.NAMESPACE, _className); Namespace methodListNamespace = ObjectiveC1_Utilities.createNamespace(_state.program,
ObjectiveC1_Utilities.createSymbol(_state.program, methodListNamespace, namespace.getName(), address); ObjectiveC1_Constants.NAMESPACE, _className);
ObjectiveC1_Utilities.createSymbol(_state.program, methodListNamespace,
namespace.getName(), address);
}
catch (Exception e) {
} }
catch (Exception e) {}
for (ObjectiveC_Method method : getMethods()) { for (ObjectiveC_Method method : getMethods()) {
method.applyTo(namespace); method.applyTo(namespace);

View file

@ -191,6 +191,9 @@ public class ObjectiveC2_DecompilerMessageAnalyzer extends AbstractAnalyzer {
} }
setReference(objcCallAddress, program, currentClassName, currentMethodName); setReference(objcCallAddress, program, currentClassName, currentMethodName);
if (instruction == null) {
return;
}
if (instruction.getComment(CodeUnit.EOL_COMMENT) != null) { if (instruction.getComment(CodeUnit.EOL_COMMENT) != null) {
return; return;
} }

View file

@ -70,21 +70,57 @@ public final class DataUtilities {
*/ */
CLEAR_SINGLE_DATA, CLEAR_SINGLE_DATA,
/** /**
* Clear all conflicting Undefined data provided data will * Clear all conflicting Undefined Data provided new data will
* fit within memory and not conflict with an * fit within memory and not conflict with an
* instruction or other defined data. Undefined refers to defined * instruction or other defined data. Undefined refers to defined
* data with the Undefined data-type. * data with the Undefined data-type (see {@link Undefined#isUndefined(DataType)}).
* @see Undefined#isUndefined(DataType)
*/ */
CLEAR_ALL_UNDEFINED_CONFLICT_DATA, CLEAR_ALL_UNDEFINED_CONFLICT_DATA,
/** /**
* Clear all conflicting data provided data will * Clear all Default Data provided new data will fit within memory and
* fit within memory and not conflict with an * not conflict with an instruction or other defined data. In this
* instruction. * context Default Data refers to all defined data with either an
* Undefined data-type (see {@link Undefined#isUndefined(DataType)}) or
* is considered a default pointer which is either:
* <ol>
* <li>A pointer without a referenced datatype (i.e., <i>addr</i>), or</li>
* <li>An auto-named pointer-typedef without a referenced datatype
* (e.g., <i>pointer __((offset(0x8)))</i>.</li>
* </ol>
*/
CLEAR_ALL_DEFAULT_CONFLICT_DATA,
/**
* Clear all conflicting data provided new data will fit within memory and
* not conflict with an instruction.
*/ */
CLEAR_ALL_CONFLICT_DATA CLEAR_ALL_CONFLICT_DATA
} }
private static boolean isDefaultData(DataType dt) {
// see ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA
if (Undefined.isUndefined(dt)) {
return true;
}
if (dt instanceof Pointer) {
Pointer p = (Pointer) dt;
dt = p.getDataType();
return dt == null || dt == DataType.DEFAULT;
}
return false;
}
private static boolean isDataClearingDenied(DataType dt, ClearDataMode clearMode) {
if ((clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA &&
!Undefined.isUndefined(dt))) {
return true;
}
if (clearMode == ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA &&
!isDefaultData(dt)) {
return true;
}
return false;
}
/** /**
* Create data where existing data may already exist. * Create data where existing data may already exist.
* @param program the program * @param program the program
@ -113,8 +149,7 @@ public final class DataUtilities {
return data; return data;
} }
if (!stackPointers && clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA && if (!stackPointers && isDataClearingDenied(existingType, clearMode)) {
!Undefined.isUndefined(existingType)) {
throw new CodeUnitInsertionException("Could not create Data at address " + addr); throw new CodeUnitInsertionException("Could not create Data at address " + addr);
} }
@ -176,12 +211,12 @@ public final class DataUtilities {
// null data; see if we are in a composite // null data; see if we are in a composite
if (clearMode == ClearDataMode.CLEAR_ALL_CONFLICT_DATA || if (clearMode == ClearDataMode.CLEAR_ALL_CONFLICT_DATA ||
clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA) { clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA ||
clearMode == ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA) {
// allow offcut addr if CLEAR_ALL_CONFLICT_DATA // allow offcut addr if CLEAR_ALL_CONFLICT_DATA
data = listing.getDataContaining(addr); data = listing.getDataContaining(addr);
if (data != null && clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA && if (data != null && isDataClearingDenied(data.getDataType(), clearMode)) {
!Undefined.isUndefined(data.getDataType())) {
data = null; // force error data = null; // force error
} }
} }
@ -267,32 +302,8 @@ public final class DataUtilities {
return extRef; return extRef;
} }
private static void validateCanCreateData(Address addr, ClearDataMode clearMode,
Listing listing, Data data) throws CodeUnitInsertionException {
if (data != null) {
return; // existing data; it us possible to create data
}
if (clearMode == ClearDataMode.CLEAR_ALL_CONFLICT_DATA ||
clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA) {
// allow offcut addr if CLEAR_ALL_CONFLICT_DATA
data = listing.getDataContaining(addr);
if (data != null && clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA &&
!Undefined.isUndefined(data.getDataType())) {
data = null; // force error
}
}
// null data implies that we cannot create data at this address
if (data == null) {
throw new CodeUnitInsertionException("Could not create Data at address " + addr);
}
}
private static void checkEnoughSpace(Program program, Address addr, int existingDataLen, private static void checkEnoughSpace(Program program, Address addr, int existingDataLen,
DataTypeInstance dti, ClearDataMode mode) throws CodeUnitInsertionException { DataTypeInstance dti, ClearDataMode clearMode) throws CodeUnitInsertionException {
// NOTE: method not invoked when clearMode == ClearDataMode.CLEAR_SINGLE_DATA // NOTE: method not invoked when clearMode == ClearDataMode.CLEAR_SINGLE_DATA
Listing listing = program.getListing(); Listing listing = program.getListing();
Address end = null; Address end = null;
@ -318,11 +329,12 @@ public final class DataUtilities {
return; return;
} }
if (mode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA && if ((clearMode == ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA ||
Undefined.isUndefined(definedData.getDataType())) { clearMode == ClearDataMode.CLEAR_ALL_DEFAULT_CONFLICT_DATA) &&
checkForDefinedData(dti, listing, newEnd, definedData.getMaxAddress()); !isDataClearingDenied(definedData.getDataType(), clearMode)) {
checkForDefinedData(dti, listing, newEnd, definedData.getMaxAddress(), clearMode);
} }
else if (mode != ClearDataMode.CLEAR_ALL_CONFLICT_DATA) { else if (clearMode != ClearDataMode.CLEAR_ALL_CONFLICT_DATA) {
throw new CodeUnitInsertionException("Not enough space to create DataType " + throw new CodeUnitInsertionException("Not enough space to create DataType " +
dti.getDataType().getDisplayName()); dti.getDataType().getDisplayName());
} }
@ -330,9 +342,9 @@ public final class DataUtilities {
} }
private static void checkForDefinedData(DataTypeInstance dti, Listing listing, Address address, private static void checkForDefinedData(DataTypeInstance dti, Listing listing, Address address,
Address end) throws CodeUnitInsertionException { Address end, ClearDataMode clearMode) throws CodeUnitInsertionException {
// ignore all defined data which is considered Undefined and may be cleared // ignore all defined data which may be cleared
while (end.compareTo(address) <= 0) { while (end.compareTo(address) <= 0) {
Data definedData = listing.getDefinedDataAfter(end); Data definedData = listing.getDefinedDataAfter(end);
if (definedData == null || if (definedData == null ||
@ -340,7 +352,7 @@ public final class DataUtilities {
return; return;
} }
if (!Undefined.isUndefined(definedData.getDataType())) { if (isDataClearingDenied(definedData.getDataType(), clearMode)) {
throw new CodeUnitInsertionException("Not enough space to create DataType " + throw new CodeUnitInsertionException("Not enough space to create DataType " +
dti.getDataType().getDisplayName()); dti.getDataType().getDisplayName());
} }