mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
Merge remote-tracking branch 'origin/GP-4834_Dan_initEmuSpFromContext'
(Closes #6427)
This commit is contained in:
commit
4a90c53c0e
2 changed files with 158 additions and 15 deletions
|
@ -390,8 +390,108 @@ public class ProgramEmulationUtils {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AddressRange allocateStackCustom(Trace trace, long snap, TraceThread thread,
|
/**
|
||||||
Program program) {
|
* Attempt allocation of the stack using the program context and the initial PC.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This examines the program context for a stack pointer value at the thread's initial program
|
||||||
|
* counter. If it has a value, this computes a range, based on the expected stack growth
|
||||||
|
* direction, of the specified size. If the range would wrap, it is truncated toe the space's
|
||||||
|
* bounds. This then attempts to create a region at the computed range to allocate the stack. If
|
||||||
|
* it already exists, an error dialog is presented, but the SP is still initialized as
|
||||||
|
* specified.
|
||||||
|
*
|
||||||
|
* @param trace the trace containing the stack and thread
|
||||||
|
* @param snap the creation snap for the new region
|
||||||
|
* @param thread the thread for which the stack is being allocated
|
||||||
|
* @param program the program being emulated (to check for stack allocation override)
|
||||||
|
* @param size the desired size of the region
|
||||||
|
* @param programPc the program counter in the program's memory map, in case SP is given by the
|
||||||
|
* program context
|
||||||
|
* @return the range allocated for the stack, or null if no SP value is set
|
||||||
|
*/
|
||||||
|
public static AddressRange allocateStackCustomByContext(Trace trace, long snap,
|
||||||
|
TraceThread thread, Program program, long size, Address programPc) {
|
||||||
|
if (program == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ProgramContext ctx = program.getProgramContext();
|
||||||
|
CompilerSpec cSpec = trace.getBaseCompilerSpec();
|
||||||
|
Register sp = cSpec.getStackPointer();
|
||||||
|
RegisterValue spVal = ctx.getRegisterValue(sp, programPc);
|
||||||
|
if (spVal == null || !spVal.hasValue()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address spAddr = cSpec.getStackBaseSpace().getAddress(spVal.getUnsignedValue().longValue());
|
||||||
|
|
||||||
|
final AddressRange alloc;
|
||||||
|
if (cSpec.stackGrowsNegative()) {
|
||||||
|
Address max = spAddr.subtractWrap(1);
|
||||||
|
Address min = spAddr.subtractWrapSpace(size);
|
||||||
|
if (min.compareTo(max) > 0) {
|
||||||
|
alloc = new AddressRangeImpl(max.getAddressSpace().getMinAddress(), max);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alloc = new AddressRangeImpl(min, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Address min = spAddr;
|
||||||
|
Address max = spAddr.addWrap(size - 1);
|
||||||
|
if (min.compareTo(max) > 0) {
|
||||||
|
alloc = new AddressRangeImpl(min, min.getAddressSpace().getMaxAddress());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alloc = new AddressRangeImpl(min, max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PathPattern patRegion = computePatternRegion(trace);
|
||||||
|
String threadName = PathUtils.isIndex(thread.getName())
|
||||||
|
? PathUtils.parseIndex(thread.getName())
|
||||||
|
: thread.getName();
|
||||||
|
String path = PathUtils.toString(
|
||||||
|
patRegion.applyKeys(alloc.getMinAddress() + "-stack " + threadName)
|
||||||
|
.getSingletonPath());
|
||||||
|
TraceMemoryManager mm = trace.getMemoryManager();
|
||||||
|
try {
|
||||||
|
return mm.createRegion(path, snap, alloc,
|
||||||
|
TraceMemoryFlag.READ, TraceMemoryFlag.WRITE).getRange();
|
||||||
|
}
|
||||||
|
catch (TraceOverlappedRegionException e) {
|
||||||
|
Msg.showError(ProgramEmulationUtils.class, null, "Stack conflict",
|
||||||
|
("The stack region %s conflicts with another: %s. " +
|
||||||
|
"You may need to initialize the stack pointer manually.").formatted(
|
||||||
|
alloc, e.getConflicts().iterator().next()));
|
||||||
|
return alloc;
|
||||||
|
}
|
||||||
|
catch (DuplicateNameException e) {
|
||||||
|
Msg.showError(ProgramEmulationUtils.class, null, "Stack conflict",
|
||||||
|
("A region already exists with the same name: %s. " +
|
||||||
|
"You may need to initialize the stack pointer manually.")
|
||||||
|
.formatted(path));
|
||||||
|
return alloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt allocation of the stack using the program's STACK block.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This tries to find a block named STACK in the emulated program. If it finds one, it will
|
||||||
|
* attempt to create a region in the trace at the mapped dynamic location. It's possible (likely
|
||||||
|
* even, for a multi-threaded emulation session) that the region already exists. In that case,
|
||||||
|
* an error dialog is displayed, but the stack pointer is still initialized to the block.
|
||||||
|
*
|
||||||
|
* @param trace the trace containing the stack and thread
|
||||||
|
* @param snap the creation snap for the new region
|
||||||
|
* @param thread the thread for which the stack is being allocated
|
||||||
|
* @param program the program being emulated (to check for stack allocation override)
|
||||||
|
* @return the range allocated for the stack, or null if no STACK block exists
|
||||||
|
*/
|
||||||
|
public static AddressRange allocateStackCustomByBlock(Trace trace, long snap,
|
||||||
|
TraceThread thread, Program program) {
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -441,23 +541,30 @@ public class ProgramEmulationUtils {
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* If successful, this will create a dynamic memory region representing the stack. If the stack
|
* If successful, this will create a dynamic memory region representing the stack. If the stack
|
||||||
* is specified by an override (STACK block) in the program, and that block overlays the image,
|
* is specified by an override (SP register context or STACK block) in the program, and that
|
||||||
* then no region is created.
|
* block overlays the image, then no region is created, but the range is still returned.
|
||||||
*
|
*
|
||||||
* @param trace the trace containing the stack and thread
|
* @param trace the trace containing the stack and thread
|
||||||
* @param snap the creation snap for the new region
|
* @param snap the creation snap for the new region
|
||||||
* @param thread the thread for which the stack is being allocated
|
* @param thread the thread for which the stack is being allocated
|
||||||
* @param program the program being emulated (to check for stack allocation override)
|
* @param program the program being emulated (to check for stack allocation override)
|
||||||
* @param size the desired size of the region
|
* @param size the desired size of the region
|
||||||
|
* @param programPc the program counter in the program's memory map, in case SP is given by the
|
||||||
|
* program context
|
||||||
* @return the range allocated for the stack
|
* @return the range allocated for the stack
|
||||||
*
|
*
|
||||||
* @throws EmulatorOutOfMemoryException if the stack cannot be allocated
|
* @throws EmulatorOutOfMemoryException if the stack cannot be allocated
|
||||||
*/
|
*/
|
||||||
public static AddressRange allocateStack(Trace trace, long snap, TraceThread thread,
|
public static AddressRange allocateStack(Trace trace, long snap, TraceThread thread,
|
||||||
Program program, long size) {
|
Program program, long size, Address programPc) {
|
||||||
AddressRange custom = allocateStackCustom(trace, snap, thread, program);
|
AddressRange customByContext =
|
||||||
if (custom != null) {
|
allocateStackCustomByContext(trace, snap, thread, program, size, programPc);
|
||||||
return custom;
|
if (customByContext != null) {
|
||||||
|
return customByContext;
|
||||||
|
}
|
||||||
|
AddressRange customByBlock = allocateStackCustomByBlock(trace, snap, thread, program);
|
||||||
|
if (customByBlock != null) {
|
||||||
|
return customByBlock;
|
||||||
}
|
}
|
||||||
// Otherwise, just search for an un-allocated block of the given size.
|
// Otherwise, just search for an un-allocated block of the given size.
|
||||||
AddressSpace space = trace.getBaseCompilerSpec().getStackBaseSpace();
|
AddressSpace space = trace.getBaseCompilerSpec().getStackBaseSpace();
|
||||||
|
@ -565,7 +672,7 @@ public class ProgramEmulationUtils {
|
||||||
TraceThread thread = spawnThread(trace, snap);
|
TraceThread thread = spawnThread(trace, snap);
|
||||||
AddressRange stack;
|
AddressRange stack;
|
||||||
try {
|
try {
|
||||||
stack = allocateStack(trace, snap, thread, program, 0x4000);
|
stack = allocateStack(trace, snap, thread, program, 0x4000, programPc);
|
||||||
}
|
}
|
||||||
catch (EmulatorOutOfMemoryException e) {
|
catch (EmulatorOutOfMemoryException e) {
|
||||||
Msg.warn(ProgramEmulationUtils.class,
|
Msg.warn(ProgramEmulationUtils.class,
|
||||||
|
|
|
@ -723,7 +723,42 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomStack() throws Exception {
|
public void testCustomStackByContext() throws Exception {
|
||||||
|
createProgram();
|
||||||
|
intoProject(program);
|
||||||
|
|
||||||
|
Memory memory = program.getMemory();
|
||||||
|
Address addrText = addr(program, 0x00400000);
|
||||||
|
Register regSP = program.getRegister("sp");
|
||||||
|
try (Transaction tx = program.openTransaction("Initialize")) {
|
||||||
|
MemoryBlock blockText = memory.createInitializedBlock(".text", addrText, 0x1000,
|
||||||
|
(byte) 0, TaskMonitor.DUMMY, false);
|
||||||
|
blockText.setExecute(true);
|
||||||
|
|
||||||
|
program.getProgramContext()
|
||||||
|
.setRegisterValue(addrText, addrText,
|
||||||
|
new RegisterValue(regSP, BigInteger.valueOf(0x00200000)));
|
||||||
|
}
|
||||||
|
|
||||||
|
programManager.openProgram(program);
|
||||||
|
waitForSwing();
|
||||||
|
codeBrowser.goTo(new ProgramLocation(program, addrText));
|
||||||
|
waitForSwing();
|
||||||
|
|
||||||
|
assertTrue(emulationPlugin.actionEmulateProgram.isEnabled());
|
||||||
|
performAction(emulationPlugin.actionEmulateProgram);
|
||||||
|
|
||||||
|
Trace trace = traceManager.getCurrentTrace();
|
||||||
|
assertNotNull(trace);
|
||||||
|
|
||||||
|
TraceThread thread = Unique.assertOne(trace.getThreadManager().getAllThreads());
|
||||||
|
TraceMemorySpace regs = trace.getMemoryManager().getMemoryRegisterSpace(thread, false);
|
||||||
|
assertEquals(new BigInteger("00200000", 16),
|
||||||
|
regs.getViewValue(0, regSP).getUnsignedValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCustomStackByBlock() throws Exception {
|
||||||
createProgram();
|
createProgram();
|
||||||
intoProject(program);
|
intoProject(program);
|
||||||
Memory memory = program.getMemory();
|
Memory memory = program.getMemory();
|
||||||
|
@ -733,7 +768,8 @@ public class DebuggerEmulationServiceTest extends AbstractGhidraHeadedDebuggerTe
|
||||||
MemoryBlock blockText = memory.createInitializedBlock(".text", addrText, 0x1000,
|
MemoryBlock blockText = memory.createInitializedBlock(".text", addrText, 0x1000,
|
||||||
(byte) 0, TaskMonitor.DUMMY, false);
|
(byte) 0, TaskMonitor.DUMMY, false);
|
||||||
blockText.setExecute(true);
|
blockText.setExecute(true);
|
||||||
memory.createUninitializedBlock("STACK", addr(program, 0x00001234), 0x1000, false);
|
memory.createUninitializedBlock(ProgramEmulationUtils.BLOCK_NAME_STACK,
|
||||||
|
addr(program, 0x00001234), 0x1000, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
programManager.openProgram(program);
|
programManager.openProgram(program);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue