Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PPC Big-endian VLE instruction emulation error #4392

Open
7ingsong opened this issue Jun 29, 2022 · 3 comments
Open

PPC Big-endian VLE instruction emulation error #4392

7ingsong opened this issue Jun 29, 2022 · 3 comments
Assignees
Labels
Feature: Processor/PowerPC Status: Internal This is being tracked internally by the Ghidra team Type: Bug Something isn't working

Comments

@7ingsong
Copy link

Describe the bug

Error during emulation of code PPC Big-endian VLE, Ghidra can't emulate the instruction after branch "se_mflr r0"

emu-error.py> Running...
Address: 0x00000000 (se_mflr r0)
Address: 0x00000002 (se_bl 0x00000010)
Address: 0x00000010 (se_mflr r0)
Emulation Error: 'Instruction decode failed (Unable to resolve constructor at 00000010), PC=00000010'
emu-error.py> Finished!

To Reproduce

image

- In CodeBrowser press F12 on address 0x0 (Disassemble PPC VLE)
                             //
                             // ram 
                             // ram:00000000-ram:0000004f
                             //
                             *************************************************************
                             *                           FUNCTION                         
                             *************************************************************
                             undefined  FUN_00000000 ()
                               assume vle = 0x1
             undefined         r3:1           <RETURN>
                             FUN_00000000
      ram:00000000  00  80             se_mflr    r0
      ram:00000002  E9  07             se_bl      FUN_00000010                                     undefined FUN_00000010()
      ram:00000004  00  90             se_mtlr    r0
      ram:00000006  00  04             se_blr
      ram:00000008  00                 ??         00h
      ram:00000009  00                 ??         00h
      ram:0000000a  00                 ??         00h
      ram:0000000b  00                 ??         00h
      ram:0000000c  00                 ??         00h
      ram:0000000d  00                 ??         00h
      ram:0000000e  00                 ??         00h
      ram:0000000f  00                 ??         00h
                             *************************************************************
                             *                           FUNCTION                         
                             *************************************************************
                             undefined  FUN_00000010 ()
                               assume vle = 0x1
             undefined         r3:1           <RETURN>
                             FUN_00000010                                    XREF[1]:     FUN_00000000:00000002 (c)   
      ram:00000010  00  80             se_mflr    r0
      ram:00000012  00  90             se_mtlr    r0
      ram:00000014  00  04             se_blr
      ram:00000016  00                 ??         00h
      ram:00000017  00                 ??         00h
      ram:00000018  00                 ??         00h
      ram:00000019  00                 ??         00h
  • Open Script Manager and create this python script
from ghidra.app.emulator import EmulatorHelper
from ghidra.app.emulator import EmulatorHelper
from ghidra.program.model.symbol import SymbolUtilities


def getAddress(offset):
    return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset)

def getSymbolAddress(symbolName):
    symbol = SymbolUtilities.getLabelOrFunctionSymbol(currentProgram, symbolName, None)
    if (symbol != None):
        return symbol.getAddress()
    else:
        raise("Failed to locate label: {}".format(symbolName))


emuHelper = EmulatorHelper(currentProgram)

codeStart=0x0
codeStop=0x6

emuHelper.writeRegister(emuHelper.getPCRegister(), codeStart)

while monitor.isCancelled() is False:
	executionAddress = emuHelper.getExecutionAddress()  
	
	if (executionAddress == getAddress(codeStop)):
		print("Emulation complete.")
		break
	try:
		print("Address: 0x{} ({})".format(executionAddress, getInstructionAt(executionAddress)))
	except:
		pass
	success = emuHelper.step(monitor)	
	if (success == False):
		lastError = emuHelper.getLastError()
		print("Emulation Error: '{}'".format(lastError))
		break

# Cleanup resources and release hold on currentProgram
emuHelper.dispose()
  • Run the script and see an error during emulation instruction "se_mflr r0"
emu-error.py> Running...
Address: 0x00000000 (se_mflr r0)
Address: 0x00000002 (se_bl 0x00000010)
Address: 0x00000010 (se_mflr r0)
Emulation Error: 'Instruction decode failed (Unable to resolve constructor at 00000010), PC=00000010'
emu-error.py> Finished!

Environment (please complete the following information):

Additional context

@7ingsong
Copy link
Author

I found a similar issue #3428

I tried to set VLE register to 1 for the region, but it doesn't help. The same error

from ghidra.app.emulator import EmulatorHelper
from ghidra.app.emulator import EmulatorHelper
from ghidra.program.model.symbol import SymbolUtilities
from ghidra.program.model.lang import RegisterValue
from java.math import BigInteger

def getAddress(offset):
    return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset)

def getSymbolAddress(symbolName):
    symbol = SymbolUtilities.getLabelOrFunctionSymbol(currentProgram, symbolName, None)
    if (symbol != None):
        return symbol.getAddress()
    else:
        raise("Failed to locate label: {}".format(symbolName))


vleReg =  currentProgram.language.getRegister("vle")
value = RegisterValue(vleReg, BigInteger.ONE)
loadedMemory = currentProgram.getMemory().getLoadedAndInitializedAddressSet()
#print("addr",loadedMemory.getMinAddress(),loadedMemory.getMaxAddress())
currentProgram.getProgramContext().setRegisterValue(getAddress(0x0), getAddress(0x50), value) 

emuHelper = EmulatorHelper(currentProgram)

codeStart=0x0
codeStop=0x6

emuHelper.writeRegister(emuHelper.getPCRegister(), codeStart)

while monitor.isCancelled() is False:
	executionAddress = emuHelper.getExecutionAddress()  
	
	if (executionAddress == getAddress(codeStop)):
		print("Emulation complete.")
		break
	
	print("Address: 0x{} ({})".format(executionAddress, getInstructionAt(executionAddress)))
	success = emuHelper.step(monitor)	
	if (success == False):
		lastError = emuHelper.getLastError()
		print("Emulation Error: '{}'".format(lastError))
		break
		
emuHelper.dispose()

The error

emu-error.py> Running...
Address: 0x00000000 (se_mflr r0)
Address: 0x00000002 (se_bl 0x00000010)
Address: 0x00000010 (se_mflr r0)
Emulation Error: 'Instruction decode failed (Unable to resolve constructor at 00000010), PC=00000010'
emu-error.py> Finished!

@GhidorahRex GhidorahRex added Type: Bug Something isn't working Feature: Processor/PowerPC Status: Triage Information is being gathered labels Jun 30, 2022
@GhidorahRex GhidorahRex self-assigned this Jun 30, 2022
@GhidorahRex
Copy link
Collaborator

GhidorahRex commented Jul 18, 2022

I'm still looking into this, but I can get the python script to run without error by adding a call to emuHelper.setContextRegister in the try block. If I set the context register at the beginning of the script it won't flow properly to other functions. What is weird here is if I get the register value I get the same value before and after .

from ghidra.app.emulator import EmulatorHelper
from ghidra.program.model.symbol import SymbolUtilities
from ghidra.program.model.symbol import SymbolUtilities
from ghidra.program.model.lang import RegisterValue
from java.math import BigInteger

def getAddress(offset):
    return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset)

def getSymbolAddress(symbolName):
    symbol = SymbolUtilities.getLabelOrFunctionSymbol(currentProgram, symbolName, None)
    if (symbol != None):
        return symbol.getAddress()
    else:
        raise("Failed to locate label: {}".format(symbolName))


emuHelper = EmulatorHelper(currentProgram)

codeStart=0x0
codeStop=0x6

emuHelper.writeRegister(emuHelper.getPCRegister(), codeStart)

while monitor.isCancelled() is False:
	executionAddress = emuHelper.getExecutionAddress()  
	
	if (executionAddress == getAddress(codeStop)):
		print("Emulation complete.")
		break
	try:
		vleReg = currentProgram.language.getRegister("vle")
		emuHelper.setContextRegister(vleReg,BigInteger.ONE)
		print("Address: 0x{} ({})".format(executionAddress, getInstructionAt(executionAddress)))
	except:
		raise
	success = emuHelper.step(monitor)	
	if (success == False):
		lastError = emuHelper.getLastError()
		print("Emulation Error: '{}'".format(lastError))
		break

# Cleanup resources and release hold on currentProgram
emuHelper.dispose()

Alternatively, replacing the emuHelper.setContextRegister(vleReg,BigInteger.ONE) call with the following also works:
emuHelper.setContextRegister(emuHelper.getContextRegister())

@GhidorahRex GhidorahRex added Status: Internal This is being tracked internally by the Ghidra team and removed Status: Triage Information is being gathered labels Aug 17, 2022
@GhidorahRex
Copy link
Collaborator

The issue here is that the emulator is not properly setting the seedContext in the disassembler. To correct it, we need to modify Emulate.java with this:

	public void setSeedContext(ProgramContext seedContext) {
		pseudoDisassembler.setSeedContext(new DisassemblerContextImpl(seedContext));
	}

Emulator.java with this:

	public void setSeedContext(ProgramContext seedContext) {
		emulator.setSeedContext(seedContext);
	}

and modify your script to either rely on the context in the program listing:

emHelper.getEmulator().setSeedContext(program.getProgramContext())

or you can just manually set the vle context variable:

ProgramContextImpl context = new ProgramContextImpl(program.getLanguage())
Register vleReg = currentProgram.language.getRegister("vle")
context.setValue(vleReg, startAddr, endAddr, BigInteger.ONE)
emulator.setSeedContext(context)

Either way, I'll get the changes to the emulator incorporated so these steps work out of the box.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature: Processor/PowerPC Status: Internal This is being tracked internally by the Ghidra team Type: Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants