mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
d4160bd88c
6 changed files with 123 additions and 136 deletions
|
@ -323,6 +323,7 @@ public class GraphClassesScript extends GhidraScript {
|
||||||
.defaultVertexColor(WebColors.PURPLE)
|
.defaultVertexColor(WebColors.PURPLE)
|
||||||
.defaultEdgeColor(WebColors.PURPLE)
|
.defaultEdgeColor(WebColors.PURPLE)
|
||||||
.defaultLayoutAlgorithm("Compact Hierarchical")
|
.defaultLayoutAlgorithm("Compact Hierarchical")
|
||||||
|
.maxNodeCount(1000)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
display.setGraph(graph, graphOptions,
|
display.setGraph(graph, graphOptions,
|
||||||
|
|
|
@ -57,7 +57,6 @@ import ghidra.test.TestEnv;
|
||||||
import ghidra.util.SystemUtilities;
|
import ghidra.util.SystemUtilities;
|
||||||
import ghidra.util.table.GhidraProgramTableModel;
|
import ghidra.util.table.GhidraProgramTableModel;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
import ghidra.util.task.TaskMonitorAdapter;
|
|
||||||
|
|
||||||
public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
|
@ -100,8 +99,6 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
env.dispose();
|
env.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStructures() throws Exception {
|
public void testStructures() throws Exception {
|
||||||
openX86ProgramInTool();
|
openX86ProgramInTool();
|
||||||
|
@ -187,15 +184,7 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
for (int element : TYPES) {
|
for (int element : TYPES) {
|
||||||
|
|
||||||
int txId = program.startTransaction("TEST");
|
tx(program, () -> program.getListing().setComment(addr, element, "Test" + element));
|
||||||
try {
|
|
||||||
program.getListing().setComment(addr, element, "Test" + element);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
program.endTransaction(txId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
program.flushEvents();
|
|
||||||
|
|
||||||
sendProgramLocation(addr, element);
|
sendProgramLocation(addr, element);
|
||||||
|
|
||||||
|
@ -368,8 +357,6 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertTrue(browser.goToField(addr, EolCommentFieldFactory.FIELD_NAME, 0, 0));
|
assertTrue(browser.goToField(addr, EolCommentFieldFactory.FIELD_NAME, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetAll() throws Exception {
|
public void testSetAll() throws Exception {
|
||||||
openX86ProgramInTool();
|
openX86ProgramInTool();
|
||||||
|
@ -405,8 +392,6 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(REPEAT, cu.getComment(CodeUnit.REPEATABLE_COMMENT));
|
assertEquals(REPEAT, cu.getComment(CodeUnit.REPEATABLE_COMMENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyButton() throws Exception {
|
public void testApplyButton() throws Exception {
|
||||||
openX86ProgramInTool();
|
openX86ProgramInTool();
|
||||||
|
@ -421,8 +406,6 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertTrue(!commentsDialog.isVisible());
|
assertTrue(!commentsDialog.isVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testModify() throws Exception {
|
public void testModify() throws Exception {
|
||||||
openX86ProgramInTool();
|
openX86ProgramInTool();
|
||||||
|
@ -436,8 +419,6 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(PRE_U, cu.getComment(CodeUnit.PRE_COMMENT));
|
assertEquals(PRE_U, cu.getComment(CodeUnit.PRE_COMMENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPromptForSaveChangesYes() throws Exception {
|
public void testPromptForSaveChangesYes() throws Exception {
|
||||||
openX86ProgramInTool();
|
openX86ProgramInTool();
|
||||||
|
@ -544,8 +525,6 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReallyBigComment() throws Exception {
|
public void testReallyBigComment() throws Exception {
|
||||||
openX86ProgramInTool();
|
openX86ProgramInTool();
|
||||||
|
@ -563,8 +542,6 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(comment, cu.getComment(CodeUnit.PRE_COMMENT));
|
assertEquals(comment, cu.getComment(CodeUnit.PRE_COMMENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNavigationFromSymbol() throws Exception {
|
public void testNavigationFromSymbol() throws Exception {
|
||||||
openX86ProgramInTool();
|
openX86ProgramInTool();
|
||||||
|
@ -685,7 +662,7 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
Address destAddr = addr(0x01008394);
|
Address destAddr = addr(0x01008394);
|
||||||
assertEquals(destAddr, browser.getCurrentLocation().getAddress());
|
assertEquals(destAddr, browser.getCurrentLocation().getAddress());
|
||||||
|
|
||||||
getProviders()[0].closeComponent();
|
runSwing(() -> getProviders()[0].closeComponent());
|
||||||
|
|
||||||
assertEquals(destAddr, browser.getCurrentLocation().getAddress());
|
assertEquals(destAddr, browser.getCurrentLocation().getAddress());
|
||||||
}
|
}
|
||||||
|
@ -697,7 +674,6 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
open8051Program();
|
open8051Program();
|
||||||
|
|
||||||
AddressFactory af = program.getAddressFactory();
|
AddressFactory af = program.getAddressFactory();
|
||||||
AddressSpace codeSpace = af.getAddressSpace("CODE");
|
|
||||||
AddressSpace extmemSpace = af.getAddressSpace("EXTMEM");
|
AddressSpace extmemSpace = af.getAddressSpace("EXTMEM");
|
||||||
|
|
||||||
Address addr = extmemSpace.getAddress(0);
|
Address addr = extmemSpace.getAddress(0);
|
||||||
|
@ -722,9 +698,7 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
assertEquals(spaceComment, cu.getComment(CodeUnit.PLATE_COMMENT));
|
assertEquals(spaceComment, cu.getComment(CodeUnit.PLATE_COMMENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************/
|
/*
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that when using the GoTo service the edit comments action
|
* Test that when using the GoTo service the edit comments action
|
||||||
* is enabled.
|
* is enabled.
|
||||||
*
|
*
|
||||||
|
@ -837,13 +811,13 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
int transactionID = program.startTransaction("Test");
|
int transactionID = program.startTransaction("Test");
|
||||||
try {
|
try {
|
||||||
memory.createInitializedBlock("test1", addr(0x1006000), 0x1000, (byte) 0,
|
memory.createInitializedBlock("test1", addr(0x1006000), 0x1000, (byte) 0,
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
TaskMonitor.DUMMY, false);
|
||||||
memory.createInitializedBlock("test2", addr(0x1008000), 0x1000, (byte) 0,
|
memory.createInitializedBlock("test2", addr(0x1008000), 0x1000, (byte) 0,
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
TaskMonitor.DUMMY, false);
|
||||||
memory.createInitializedBlock("test3", addr(0x100b000), 0x1000, (byte) 0,
|
memory.createInitializedBlock("test3", addr(0x100b000), 0x1000, (byte) 0,
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
TaskMonitor.DUMMY, false);
|
||||||
memory.createInitializedBlock("test4", addr(0xf0000000), 0x2000, (byte) 0,
|
memory.createInitializedBlock("test4", addr(0xf0000000), 0x2000, (byte) 0,
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
TaskMonitor.DUMMY, false);
|
||||||
|
|
||||||
SymbolTable st = program.getSymbolTable();
|
SymbolTable st = program.getSymbolTable();
|
||||||
Namespace ns = st.createNameSpace(null, "Deadpool", SourceType.USER_DEFINED);
|
Namespace ns = st.createNameSpace(null, "Deadpool", SourceType.USER_DEFINED);
|
||||||
|
@ -854,8 +828,11 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
program.endTransaction(transactionID, true);
|
program.endTransaction(transactionID, true);
|
||||||
}
|
}
|
||||||
// write the file to the project to test external navigation for comment annotation
|
// write the file to the project to test external navigation for comment annotation
|
||||||
env.getProject().getProjectData().getRootFolder().createFile("Test", program,
|
env.getProject()
|
||||||
TaskMonitor.DUMMY);
|
.getProjectData()
|
||||||
|
.getRootFolder()
|
||||||
|
.createFile("Test", program,
|
||||||
|
TaskMonitor.DUMMY);
|
||||||
env.showTool(program);
|
env.showTool(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,9 +848,9 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
int transactionID = program.startTransaction("Test");
|
int transactionID = program.startTransaction("Test");
|
||||||
try {
|
try {
|
||||||
memory.createInitializedBlock("EEPROM", extmemSpace.getAddress(0), 0x100, (byte) 0,
|
memory.createInitializedBlock("EEPROM", extmemSpace.getAddress(0), 0x100, (byte) 0,
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
TaskMonitor.DUMMY, false);
|
||||||
memory.createInitializedBlock("CODE", codeSpace.getAddress(0), 0x100, (byte) 0,
|
memory.createInitializedBlock("CODE", codeSpace.getAddress(0), 0x100, (byte) 0,
|
||||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
TaskMonitor.DUMMY, false);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
program.endTransaction(transactionID, true);
|
program.endTransaction(transactionID, true);
|
||||||
|
@ -884,23 +861,23 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Reference addReference(long fromOffset, long toOffset, RefType refType) {
|
private Reference addReference(long fromOffset, long toOffset, RefType refType) {
|
||||||
int transactionID = program.startTransaction("Add Reference");
|
|
||||||
try {
|
return modifyProgram(program, p -> {
|
||||||
return program.getReferenceManager().addMemoryReference(addr(fromOffset),
|
return p.getReferenceManager()
|
||||||
addr(toOffset), refType, SourceType.USER_DEFINED, 0);
|
.addMemoryReference(addr(fromOffset),
|
||||||
}
|
addr(toOffset), refType, SourceType.USER_DEFINED, 0);
|
||||||
finally {
|
});
|
||||||
program.endTransaction(transactionID, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function addFunction(String name, long functionEntry, int size) throws Exception {
|
private Function addFunction(String name, long functionEntry, int size) throws Exception {
|
||||||
int transactionID = program.startTransaction("Add Function");
|
|
||||||
try {
|
return modifyProgram(program, p -> {
|
||||||
|
|
||||||
Function function =
|
Function function =
|
||||||
program.getFunctionManager().createFunction(name, addr(functionEntry),
|
p.getFunctionManager()
|
||||||
new AddressSet(addr(functionEntry), addr(functionEntry + size - 1)),
|
.createFunction(name, addr(functionEntry),
|
||||||
SourceType.USER_DEFINED);
|
new AddressSet(addr(functionEntry), addr(functionEntry + size - 1)),
|
||||||
|
SourceType.USER_DEFINED);
|
||||||
ReturnParameterImpl returnParam =
|
ReturnParameterImpl returnParam =
|
||||||
new ReturnParameterImpl(IntegerDataType.dataType, program);
|
new ReturnParameterImpl(IntegerDataType.dataType, program);
|
||||||
ParameterImpl param1 = new ParameterImpl("p1", ByteDataType.dataType, program);
|
ParameterImpl param1 = new ParameterImpl("p1", ByteDataType.dataType, program);
|
||||||
|
@ -912,10 +889,7 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, true, SourceType.USER_DEFINED,
|
FunctionUpdateType.DYNAMIC_STORAGE_FORMAL_PARAMS, true, SourceType.USER_DEFINED,
|
||||||
param1, param2);
|
param1, param2);
|
||||||
return function;
|
return function;
|
||||||
}
|
});
|
||||||
finally {
|
|
||||||
program.endTransaction(transactionID, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureTool(PluginTool pluginTool) throws Exception {
|
private void configureTool(PluginTool pluginTool) throws Exception {
|
||||||
|
@ -961,8 +935,7 @@ public class CommentsPluginTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
private void resetFormatOptions(CodeBrowserPlugin codeBrowserPlugin) {
|
private void resetFormatOptions(CodeBrowserPlugin codeBrowserPlugin) {
|
||||||
Options fieldOptions = codeBrowserPlugin.getFormatManager().getFieldOptions();
|
Options fieldOptions = codeBrowserPlugin.getFormatManager().getFieldOptions();
|
||||||
List<String> names = fieldOptions.getOptionNames();
|
List<String> names = fieldOptions.getOptionNames();
|
||||||
for (int i = 0; i < names.size(); i++) {
|
for (String name : names) {
|
||||||
String name = names.get(i);
|
|
||||||
if (!name.startsWith("Format Code")) {
|
if (!name.startsWith("Format Code")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,9 @@ import ghidra.program.model.block.CodeBlock;
|
||||||
import ghidra.program.model.block.IsolatedEntrySubModel;
|
import ghidra.program.model.block.IsolatedEntrySubModel;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
import ghidra.program.model.mem.*;
|
||||||
import ghidra.program.model.mem.DumbMemBufferImpl;
|
|
||||||
import ghidra.program.model.mem.MemoryAccessException;
|
|
||||||
import ghidra.program.model.symbol.*;
|
import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.exception.*;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
|
@ -279,34 +277,9 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to determine if the given instruction is a terminating instruction (it return, ...)
|
* Method to create the first function after the last terminating function before the given
|
||||||
* @param instruction the given instruction
|
* address which is in the middle of undefined bytes
|
||||||
* @return true if the given instruction is a terminating instruction, false otherwise
|
* @param address the given address
|
||||||
*/
|
|
||||||
public boolean isTerminatingInstruction(Instruction instruction) {
|
|
||||||
|
|
||||||
FlowType flowType = instruction.getFlowType();
|
|
||||||
FlowType overrideType =
|
|
||||||
FlowOverride.getModifiedFlowType(flowType, instruction.getFlowOverride());
|
|
||||||
|
|
||||||
if (flowType.isTerminal() || overrideType.isTerminal()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Function functionContaining = getFunctionContaining(instruction.getAddress());
|
|
||||||
if (functionContaining != null) {
|
|
||||||
if (functionContaining.isThunk() && flowType.isJump()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (flowType.isJump()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to create the first function after the last terminating function before the given address
|
|
||||||
* @param address the given addres
|
|
||||||
* @param expectedFiller the expected filler byte value
|
* @param expectedFiller the expected filler byte value
|
||||||
* @return the created function or null if not created
|
* @return the created function or null if not created
|
||||||
*/
|
*/
|
||||||
|
@ -314,12 +287,33 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
|
|
||||||
PseudoDisassembler pseudoDisassembler = new PseudoDisassembler(currentProgram);
|
PseudoDisassembler pseudoDisassembler = new PseudoDisassembler(currentProgram);
|
||||||
|
|
||||||
|
// skip any undefineds and get the defined instruction before the given address
|
||||||
Instruction instructionBefore = getInstructionBefore(address);
|
Instruction instructionBefore = getInstructionBefore(address);
|
||||||
|
|
||||||
if (instructionBefore == null || !isTerminatingInstruction(instructionBefore)) {
|
if (instructionBefore == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Address instBeforeAddr = instructionBefore.getAddress();
|
||||||
|
|
||||||
|
Memory memory = currentProgram.getMemory();
|
||||||
|
if (!memory.getBlock(address).equals(memory.getBlock(instBeforeAddr))) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set some arbritrary limit on how far back to go
|
||||||
|
if (address.subtract(instBeforeAddr) > 2000) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the instruction before all the undefines bytes doesn't indicate that it is the end
|
||||||
|
// of a function or an end of a range of a function then return
|
||||||
|
FlowType flowType = instructionBefore.getFlowType();
|
||||||
|
if (!flowType.isTerminal() && !flowType.isJump()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get the last address in the instruction
|
||||||
Address maxAddress = instructionBefore.getMaxAddress();
|
Address maxAddress = instructionBefore.getMaxAddress();
|
||||||
int maxLen = (int) (address.getOffset() - maxAddress.getOffset());
|
int maxLen = (int) (address.getOffset() - maxAddress.getOffset());
|
||||||
if (maxLen <= 0) {
|
if (maxLen <= 0) {
|
||||||
|
@ -328,6 +322,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
|
|
||||||
int offset = 1;
|
int offset = 1;
|
||||||
|
|
||||||
|
// skip the filler
|
||||||
Byte filler;
|
Byte filler;
|
||||||
try {
|
try {
|
||||||
filler = getByte(maxAddress.add(offset));
|
filler = getByte(maxAddress.add(offset));
|
||||||
|
@ -345,6 +340,8 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
|
|
||||||
Address functionStart = maxAddress.add(offset);
|
Address functionStart = maxAddress.add(offset);
|
||||||
|
|
||||||
|
// check to see if the address after the instruction and filler is the start of a valid
|
||||||
|
// subroutine
|
||||||
if (!pseudoDisassembler.isValidSubroutine(functionStart, true)) {
|
if (!pseudoDisassembler.isValidSubroutine(functionStart, true)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -352,6 +349,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
disassemble(functionStart);
|
disassemble(functionStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if so, create a function there
|
||||||
Function function = createFunction(functionStart, null);
|
Function function = createFunction(functionStart, null);
|
||||||
|
|
||||||
return function;
|
return function;
|
||||||
|
@ -451,7 +449,6 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
|
|
||||||
Byte filler = determineFillerByte();
|
Byte filler = determineFillerByte();
|
||||||
if (filler == null) {
|
if (filler == null) {
|
||||||
// println("Can't determine filler byte so cannot create undefined functions");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +466,6 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
|
|
||||||
Function newFunction = createFunctionBefore(address, filler);
|
Function newFunction = createFunctionBefore(address, filler);
|
||||||
if (newFunction == null) {
|
if (newFunction == null) {
|
||||||
//println("Can't find function containing " + address.toString());
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -542,27 +538,6 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
return subroutineAddresses;
|
return subroutineAddresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to make the given function a thiscall
|
|
||||||
* @param function the given function
|
|
||||||
* @throws InvalidInputException if issues setting return type
|
|
||||||
* @throws DuplicateNameException if try to create same symbol name already in namespace
|
|
||||||
*/
|
|
||||||
public void makeFunctionThiscall(Function function)
|
|
||||||
throws InvalidInputException, DuplicateNameException {
|
|
||||||
|
|
||||||
if (function.getCallingConventionName().equals("__thiscall")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: if you pass a Function arg you should use its program not currentProgram
|
|
||||||
ReturnParameterImpl returnType =
|
|
||||||
new ReturnParameterImpl(function.getSignature().getReturnType(), currentProgram);
|
|
||||||
|
|
||||||
function.updateFunction("__thiscall", returnType,
|
|
||||||
FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, function.getSignatureSource(),
|
|
||||||
function.getParameters());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to get a list of symbols either matching exactly (if exact flag is true) or containing (if exact flag is false) the given symbol name
|
* Method to get a list of symbols either matching exactly (if exact flag is true) or containing (if exact flag is false) the given symbol name
|
||||||
|
@ -1009,7 +984,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to add the given comment to an existing plate comment unless it already exists in the comment
|
* Method to add the given string to a plate comment unless the string already exists in it.
|
||||||
* @param address the given address
|
* @param address the given address
|
||||||
* @param comment the comment to add to the plate comment at the given address
|
* @param comment the comment to add to the plate comment at the given address
|
||||||
*/
|
*/
|
||||||
|
@ -1018,6 +993,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||||
String plateComment = getPlateComment(address);
|
String plateComment = getPlateComment(address);
|
||||||
|
|
||||||
if (plateComment == null) {
|
if (plateComment == null) {
|
||||||
|
setPlateComment(address, comment);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1820,6 +1820,9 @@ public class RTTIGccClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
// findRealVBaseFunctions(recoveredClasses);
|
// findRealVBaseFunctions(recoveredClasses);
|
||||||
|
|
||||||
|
// make constructors and destructors this calls
|
||||||
|
makeConstructorsAndDestructorsThiscalls(recoveredClasses);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructureDataType createClassTypeInfoStructure() {
|
private StructureDataType createClassTypeInfoStructure() {
|
||||||
|
|
|
@ -1333,6 +1333,9 @@ public class RTTIWindowsClassRecoverer extends RTTIClassRecoverer {
|
||||||
|
|
||||||
findRealVBaseFunctions(recoveredClasses);
|
findRealVBaseFunctions(recoveredClasses);
|
||||||
|
|
||||||
|
// make constructors and destructors _thiscalls
|
||||||
|
makeConstructorsAndDestructorsThiscalls(recoveredClasses);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -33,6 +33,7 @@ import ghidra.program.database.data.DataTypeUtilities;
|
||||||
import ghidra.program.flatapi.FlatProgramAPI;
|
import ghidra.program.flatapi.FlatProgramAPI;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.program.model.lang.CompilerSpec;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
import ghidra.program.model.listing.Function.FunctionUpdateType;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
|
@ -110,8 +111,9 @@ public class RecoveredClassHelper {
|
||||||
List<Function> allDestructors = new ArrayList<Function>();
|
List<Function> allDestructors = new ArrayList<Function>();
|
||||||
List<Function> allInlinedConstructors = new ArrayList<Function>();
|
List<Function> allInlinedConstructors = new ArrayList<Function>();
|
||||||
List<Function> allInlinedDestructors = new ArrayList<Function>();
|
List<Function> allInlinedDestructors = new ArrayList<Function>();
|
||||||
|
List<Function> nonClassInlines = new ArrayList<Function>();
|
||||||
|
|
||||||
List<Namespace> badFIDNamespaces = new ArrayList<Namespace>();
|
Set<Namespace> badFIDNamespaces = new HashSet<Namespace>();
|
||||||
List<Structure> badFIDStructures = new ArrayList<Structure>();
|
List<Structure> badFIDStructures = new ArrayList<Structure>();
|
||||||
|
|
||||||
List<Function> badFIDFunctions = new ArrayList<Function>();
|
List<Function> badFIDFunctions = new ArrayList<Function>();
|
||||||
|
@ -1951,9 +1953,6 @@ public class RecoveredClassHelper {
|
||||||
createVftableOrderMapping(recoveredClass);
|
createVftableOrderMapping(recoveredClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not already, make function a thiscall
|
|
||||||
extendedFlatAPI.makeFunctionThiscall(constructorFunction);
|
|
||||||
|
|
||||||
recoveredClass.addConstructor(constructorFunction);
|
recoveredClass.addConstructor(constructorFunction);
|
||||||
addToAllConstructors(constructorFunction);
|
addToAllConstructors(constructorFunction);
|
||||||
}
|
}
|
||||||
|
@ -1969,9 +1968,6 @@ public class RecoveredClassHelper {
|
||||||
Function inlinedConstructorFunction)
|
Function inlinedConstructorFunction)
|
||||||
throws InvalidInputException, DuplicateNameException {
|
throws InvalidInputException, DuplicateNameException {
|
||||||
|
|
||||||
//If not already, make function a thiscall
|
|
||||||
extendedFlatAPI.makeFunctionThiscall(inlinedConstructorFunction);
|
|
||||||
|
|
||||||
recoveredClass.addInlinedConstructor(inlinedConstructorFunction);
|
recoveredClass.addInlinedConstructor(inlinedConstructorFunction);
|
||||||
addToAllInlinedConstructors(inlinedConstructorFunction);
|
addToAllInlinedConstructors(inlinedConstructorFunction);
|
||||||
}
|
}
|
||||||
|
@ -1986,9 +1982,6 @@ public class RecoveredClassHelper {
|
||||||
public void addDestructorToClass(RecoveredClass recoveredClass, Function destructorFunction)
|
public void addDestructorToClass(RecoveredClass recoveredClass, Function destructorFunction)
|
||||||
throws InvalidInputException, DuplicateNameException {
|
throws InvalidInputException, DuplicateNameException {
|
||||||
|
|
||||||
//If not already, make function a thiscall
|
|
||||||
extendedFlatAPI.makeFunctionThiscall(destructorFunction);
|
|
||||||
|
|
||||||
recoveredClass.addDestructor(destructorFunction);
|
recoveredClass.addDestructor(destructorFunction);
|
||||||
addToAllDestructors(destructorFunction);
|
addToAllDestructors(destructorFunction);
|
||||||
}
|
}
|
||||||
|
@ -2004,9 +1997,6 @@ public class RecoveredClassHelper {
|
||||||
Function inlinedDestructorFunction)
|
Function inlinedDestructorFunction)
|
||||||
throws InvalidInputException, DuplicateNameException {
|
throws InvalidInputException, DuplicateNameException {
|
||||||
|
|
||||||
//If not already, make function a thiscall
|
|
||||||
extendedFlatAPI.makeFunctionThiscall(inlinedDestructorFunction);
|
|
||||||
|
|
||||||
recoveredClass.addInlinedDestructor(inlinedDestructorFunction);
|
recoveredClass.addInlinedDestructor(inlinedDestructorFunction);
|
||||||
addToAllInlinedDestructors(inlinedDestructorFunction);
|
addToAllInlinedDestructors(inlinedDestructorFunction);
|
||||||
}
|
}
|
||||||
|
@ -2255,14 +2245,14 @@ public class RecoveredClassHelper {
|
||||||
public void makeFunctionThiscall(Function function)
|
public void makeFunctionThiscall(Function function)
|
||||||
throws InvalidInputException, DuplicateNameException {
|
throws InvalidInputException, DuplicateNameException {
|
||||||
|
|
||||||
if (function.getCallingConventionName().equals("__thiscall")) {
|
if (function.getCallingConventionName().equals(CompilerSpec.CALLING_CONVENTION_thiscall)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnParameterImpl returnType =
|
ReturnParameterImpl returnType =
|
||||||
new ReturnParameterImpl(function.getSignature().getReturnType(), program);
|
new ReturnParameterImpl(function.getSignature().getReturnType(), program);
|
||||||
|
|
||||||
function.updateFunction("__thiscall", returnType,
|
function.updateFunction(CompilerSpec.CALLING_CONVENTION_thiscall, returnType,
|
||||||
FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, function.getSignatureSource(),
|
FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS, true, function.getSignatureSource(),
|
||||||
function.getParameters());
|
function.getParameters());
|
||||||
}
|
}
|
||||||
|
@ -3145,11 +3135,10 @@ public class RecoveredClassHelper {
|
||||||
notInFunctionVftableRefs.add(addr);
|
notInFunctionVftableRefs.add(addr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
boolean functionCreated =
|
boolean functionCreated = extendedFlatAPI.createFunction(program, addr);
|
||||||
extendedFlatAPI.createFunction(prog, addr);
|
if (!functionCreated) {
|
||||||
if (!functionCreated) {
|
notInFunctionVftableRefs.add(addr);
|
||||||
notInFunctionVftableRefs.add(addr);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3806,11 +3795,13 @@ public class RecoveredClassHelper {
|
||||||
if (bookmarkComment.contains("Single Match")) {
|
if (bookmarkComment.contains("Single Match")) {
|
||||||
|
|
||||||
Symbol symbol = symbolTable.getPrimarySymbol(functionAddress);
|
Symbol symbol = symbolTable.getPrimarySymbol(functionAddress);
|
||||||
|
|
||||||
if (symbol != null && symbol.getSource() == SourceType.ANALYSIS &&
|
if (symbol != null && symbol.getSource() == SourceType.ANALYSIS &&
|
||||||
!symbol.getName().equals(name) && !symbol.getParentNamespace().equals(namespace)) {
|
!symbol.getName().equals(name) && !symbol.getParentNamespace().equals(namespace)) {
|
||||||
// add to list of bad namespaces to be cleaned up later
|
// add to list of bad namespaces to be cleaned up later
|
||||||
if (!badFIDNamespaces.contains(symbol.getParentNamespace())) {
|
Namespace parentNamespace = symbol.getParentNamespace();
|
||||||
badFIDNamespaces.add(symbol.getParentNamespace());
|
if (!parentNamespace.isGlobal()) {
|
||||||
|
badFIDNamespaces.add(parentNamespace);
|
||||||
}
|
}
|
||||||
extendedFlatAPI.addUniqueStringToPlateComment(functionAddress,
|
extendedFlatAPI.addUniqueStringToPlateComment(functionAddress,
|
||||||
"***** Removed Bad FID Symbol *****");
|
"***** Removed Bad FID Symbol *****");
|
||||||
|
@ -4426,6 +4417,11 @@ public class RecoveredClassHelper {
|
||||||
monitor.checkCanceled();
|
monitor.checkCanceled();
|
||||||
Namespace badNamespace = badNamespaceIterator.next();
|
Namespace badNamespace = badNamespaceIterator.next();
|
||||||
|
|
||||||
|
// global namespace shouldn't be on list but check anyway
|
||||||
|
if (badNamespace.isGlobal()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// delete empty namespace and parent namespaces
|
// delete empty namespace and parent namespaces
|
||||||
if (!extendedFlatAPI.hasSymbolsInNamespace(badNamespace)) {
|
if (!extendedFlatAPI.hasSymbolsInNamespace(badNamespace)) {
|
||||||
removeEmptyNamespaces(badNamespace);
|
removeEmptyNamespaces(badNamespace);
|
||||||
|
@ -5965,6 +5961,7 @@ public class RecoveredClassHelper {
|
||||||
|
|
||||||
// remove from the allConstructors too
|
// remove from the allConstructors too
|
||||||
addInlinedConstructorToClass(recoveredClass, constructor);
|
addInlinedConstructorToClass(recoveredClass, constructor);
|
||||||
|
nonClassInlines.add(constructor);
|
||||||
constructorIterator.remove();
|
constructorIterator.remove();
|
||||||
removeFromAllConstructors(constructor);
|
removeFromAllConstructors(constructor);
|
||||||
|
|
||||||
|
@ -6966,6 +6963,40 @@ public class RecoveredClassHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void makeConstructorsAndDestructorsThiscalls(List<RecoveredClass> recoveredClasses)
|
||||||
|
throws CancelledException, InvalidInputException, DuplicateNameException {
|
||||||
|
|
||||||
|
if (recoveredClasses.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Function> allConstructorDestructorFunctions = new ArrayList<Function>();
|
||||||
|
|
||||||
|
for (RecoveredClass recoveredClass : recoveredClasses) {
|
||||||
|
|
||||||
|
monitor.checkCanceled();
|
||||||
|
|
||||||
|
allConstructorDestructorFunctions.addAll(recoveredClass.getConstructorList());
|
||||||
|
allConstructorDestructorFunctions.addAll(recoveredClass.getDestructorList());
|
||||||
|
allConstructorDestructorFunctions.addAll(recoveredClass.getInlinedConstructorList());
|
||||||
|
allConstructorDestructorFunctions.addAll(recoveredClass.getInlinedDestructorList());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allConstructorDestructorFunctions.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the inlines that are not in their expected class -- still want the inline
|
||||||
|
// comments later in processing but don't make them this calls
|
||||||
|
allConstructorDestructorFunctions.removeAll(nonClassInlines);
|
||||||
|
|
||||||
|
for (Function function : allConstructorDestructorFunctions) {
|
||||||
|
monitor.checkCanceled();
|
||||||
|
makeFunctionThiscall(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to create <class_name>_data structure for given class
|
* Method to create <class_name>_data structure for given class
|
||||||
* @param recoveredClass the class
|
* @param recoveredClass the class
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue