M68000 OperandTypes not being set properly
See original GitHub issueDescribe the bug For instructions where one of the operands is a register, the OperandTypes are not always set the same.
To Reproduce Steps to reproduce the behavior:
- In a Ghidra Script, iterate through instructions, and then through the the operands of each instruction.
- For each operand, print out the raw bitstring value of OperandType, in addition to Types that corresponds to.
Expected behavior Unless I am misunderstanding how these flags work, operands that are using the same addressing modes (e.g. offset from the address in a register) should have the same resulting operand types.
Screenshots
Here, the second operand is an address, but is not marked as one (output from my own script, attached)
instruction: move.b (0x070a079c).l,(0x4,A5)
operand: [0x4, A5]
object type: <type 'ghidra.program.model.scalar.Scalar'>
object type: <type 'ghidra.program.model.lang.Register'>
bitstring: 10000000000000000000000
operandtype: DYNAMIC
But here another operand is using the same addressing mode and is marked as an ADDRESS
in addition to DYNAMIC
instruction: movea.l (-0x380,A6),A5
operand: [-0x380, A6]
object type: <type 'ghidra.program.model.scalar.Scalar'>
object type: <type 'ghidra.program.model.lang.Register'>
bitstring: 10000000010000000000000
operandtype: DYNAMIC, ADDRESS
Here is another example, where in one case a register is properly flagged as REGISTER
,
instruction: move.l #0x288,D0
operand: [D0]
object type: <type 'ghidra.program.model.lang.Register'>
bitstring: 1000000000
operandtype: REGISTER
but here a register is not
instruction: mulu.l #0x406,D0
operand: [D0]
object type: <type 'ghidra.program.model.lang.Register'>
bitstring: 10000000000000000000000
operandtype: DYNAMIC
Attachments My (hacky) Ghidra script to print out this information:
# Print operand types for each operands
#
# @author balex
# @category M68K
from ghidra import *
# from https://ghidra.re/ghidra_docs/api/constant-values.html#ghidra.program.model.lang.OperandType
operand_type = {
0: "READ",
1: "WRITE",
2: "INDIRECT",
3: "IMMEDIATE",
4: "RELATIVE",
5: "IMPLICIT",
6: "CODE",
7: "DATA",
8: "PORT",
9: "REGISTER",
10: "LIST",
11: "FLAG",
12: "TEXT",
13: "ADDRESS",
14: "SCALAR",
15: "BIT",
16: "BYTE",
17: "WORD",
18: "QUADWORD",
19: "SIGNED",
20: "FLOAT",
21: "COP",
22: "DYNAMIC"
}
def get_types(value):
bitstr = "{0:b}".format(value)
length = len(bitstr)
print(" bitstring: " + bitstr)
types = list()
for i, bit in enumerate(bitstr):
pos = length - i - 1
if int(bit): types.append(operand_type[pos])
return types
listing = currentProgram.getListing()
fm = currentProgram.getFunctionManager()
for func in fm.getFunctions(True):
addr = func.getBody()
instructs = listing.getInstructions(addr, True)
for ins in instructs:
for i in range(ins.getNumOperands()):
oper = ins.getOpObjects(i)
if len(oper):
print("================")
print('instruction: ' + str(ins))
print(' operand: ' + str(list(oper)))
for obj in oper:
print('object type: ' + str(type(obj)))
print('operandtype: ' + ', '.join(get_types(ins.getOperandType(i))))
Environment (please complete the following information):
- OS: Manjaro Linux 21.2.6
- Java Version: 18.0.1.1
- Ghidra Version: 10.1.3
- Ghidra Origin:
pacman
Issue Analytics
- State:
- Created a year ago
- Comments:5 (1 by maintainers)
@alex-bellon API appears to be working as intended - albeit confusing at times. Closing ticket, but feel free to add comments/questions if you like.
Case 1: For your
movea.l (-0x380,A6),A5
case the presence of a memory/stack/external reference on the first operand will cause the addition of the ADDRESS type to what the instruction prototype generated (i.e., DYNAMIC). This reference is likely missing from the second. Analysis in some case is able to determine the resulting address associated with a computed operand and add such a reference.Case 2: The
move.l #0x288,D0
uses a simple register attach on the operand while the later onemulu.l #0x406,D0
usessubmul
which does not export a value for the operand. Without more investigation it is unclear to me why thismulu.l
instruction has been implemented in such a complex manner.The DYNAMIC type is a default if no other specific type can be determined.
You can also look into the
Instruction.getDefaultOperandRepresentationList(int operand)
which will include objects such as Scalar, Address, Register which are specific to what you see rendered for an operand. This method avoids any extra markup which may occur when formatted for the listing display.