mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
Merge remote-tracking branch
'origin/GP-1774_James_JVM_switch_improvements--SQUASHED' (Closes #3980, Closes #3981)
This commit is contained in:
commit
17a9c07972
4 changed files with 33 additions and 39 deletions
|
@ -236,7 +236,7 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain
|
|||
if (column == 0) {
|
||||
return "";
|
||||
}
|
||||
return "Operand-" + column;
|
||||
return "Operand-" + (column - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
endian="big"
|
||||
size="32"
|
||||
variant="default"
|
||||
version="1.0"
|
||||
version="1.1"
|
||||
slafile="JVM.sla"
|
||||
processorspec="JVM.pspec"
|
||||
manualindexfile="../manuals/JVM.idx"
|
||||
|
|
|
@ -1721,19 +1721,18 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
|
|||
# lookupswitch
|
||||
##################################################################################################
|
||||
|
||||
LookupSwitch_match:match _offset is matchbyte1; matchbyte2; matchbyte3; matchbyte4; offsetbyte1; offsetbyte2; offsetbyte3; offsetbyte4 [match = (matchbyte1 << 24) | (matchbyte2 << 16) | (matchbyte3 << 8) | (matchbyte4); _offset = (offsetbyte1 << 24) | (offsetbyte2 << 16) | (offsetbyte3 << 8) | (offsetbyte4); ]
|
||||
#compute and display one match,offset pair
|
||||
LookupSwitch_match:match _offset is matchbyte1; matchbyte2; matchbyte3; matchbyte4; offsetbyte1; offsetbyte2; offsetbyte3; offsetbyte4 [match = (matchbyte1 << 24) | (matchbyte2 << 16) | (matchbyte3 << 8) | (matchbyte4); _offset = inst_start + ((offsetbyte1 << 24) | (offsetbyte2 << 16) | (offsetbyte3 << 8) | (offsetbyte4)); ]
|
||||
{
|
||||
}
|
||||
|
||||
LookupSwitch_case:"lscase" lscase is (in_lookup_switch=1 & in_table_switch=0) [ lscase = switch_num; switch_num = switch_num - 1;]
|
||||
#consume one match,offset pair and decrement the switch number
|
||||
:^LookupSwitch_match, instruction is (in_lookup_switch=1 & in_table_switch=0); LookupSwitch_match; instruction [switch_num = switch_num - 1;]
|
||||
{
|
||||
}
|
||||
|
||||
:^LookupSwitch_case LookupSwitch_match, instruction is (in_lookup_switch=1 & in_table_switch=0); LookupSwitch_case; LookupSwitch_match; instruction
|
||||
{
|
||||
}
|
||||
|
||||
:"lscase" lscase LookupSwitch_match is (in_lookup_switch=1 & switch_num=1 & in_table_switch=0); LookupSwitch_match [in_lookup_switch=0; lscase=switch_num; ]
|
||||
#leave the switch statement
|
||||
:""LookupSwitch_match is (in_lookup_switch=1 & switch_num=1 & in_table_switch=0); LookupSwitch_match [in_lookup_switch=0;]
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1744,14 +1743,14 @@ padSwitch: "" is alignmentPad = 2 & padVal & op ; pad1; pad2 { export *[const]:
|
|||
padSwitch: "" is alignmentPad = 1 & padVal & op ; pad1 { export *[const]:1 padVal; }
|
||||
padSwitch: "" is alignmentPad = 0 & padVal & op { export *[const]:1 padVal; }
|
||||
|
||||
dolookupswitch: _default, npairs is alignmentPad & defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4; npairsbyte1; npairsbyte2; npairsbyte3; npairsbyte4 [ npairs = (npairsbyte1 << 24) | (npairsbyte2 << 16) | (npairsbyte3 << 8) | npairsbyte4; _default = (defaultbyte1 << 24) | (defaultbyte2 << 16) | (defaultbyte3 << 8) | (defaultbyte4); switch_num = npairs; in_lookup_switch = 1;]
|
||||
#Note: "Default" constructor does not play nice with switchAssist injection...
|
||||
dolookupswitch: _default, npairs is alignmentPad & defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4; npairsbyte1; npairsbyte2; npairsbyte3; npairsbyte4 [ npairs = (npairsbyte1 << 24) | (npairsbyte2 << 16) | (npairsbyte3 << 8) | npairsbyte4; _default = inst_start + ((defaultbyte1 << 24) | (defaultbyte2 << 16) | (defaultbyte3 << 8) | defaultbyte4); switch_num = npairs; in_lookup_switch = 1;]
|
||||
{
|
||||
_padding:1 = alignmentPad;
|
||||
_opcodeAddr:$(SIZE) = inst_start;
|
||||
_defaultAddr:$(SIZE) = inst_start + _default;
|
||||
_key:$(SIZE) = 0;
|
||||
local _padding:1 = alignmentPad;
|
||||
local _opcodeAddr:$(SIZE) = inst_start;
|
||||
local _key:$(SIZE) = 0;
|
||||
pop(_key);
|
||||
_address:$(SIZE) = switchAssist(_key,_opcodeAddr,_padding,_defaultAddr,npairs:$(SIZE));
|
||||
local _address:$(SIZE) = switchAssist(_key,_opcodeAddr,_padding,_default:$(SIZE),npairs:$(SIZE));
|
||||
goto [ _address ];
|
||||
}
|
||||
|
||||
|
@ -2013,20 +2012,29 @@ _value :$(DOUBLE_SIZE) = 0;
|
|||
# tableswitch
|
||||
########################################################################################################################
|
||||
|
||||
#compute and display one switch offset
|
||||
Switch_offset:_offset is offsetbyte1; offsetbyte2; offsetbyte3; offsetbyte4 [ _offset = inst_start + ((offsetbyte1<<24) | (offsetbyte2<<16) | (offsetbyte3<<8) | offsetbyte4); ]
|
||||
{
|
||||
}
|
||||
|
||||
Switch_case:"case" case is (in_table_switch=1) [ case = switch_high-switch_num; switch_num=switch_num-1; ]
|
||||
# Switch entry that's not the last one.
|
||||
# no pcode def - this construction is just for consuming all of the bytes of a tableswitch instructions
|
||||
# decrements the switch number
|
||||
:^Switch_offset, instruction is (in_table_switch=1 & in_lookup_switch=0); Switch_offset; instruction [switch_num = switch_num - 1;]
|
||||
{
|
||||
}
|
||||
|
||||
#Last switch entry. Get out of switch context.
|
||||
:""Switch_offset is (in_table_switch=1 & in_lookup_switch=0 &switch_num=0); Switch_offset [ in_table_switch=0; ]
|
||||
{
|
||||
}
|
||||
|
||||
dotableswitch: Default, low, high is alignmentPad & Default;lowbyte1; lowbyte2; lowbyte3; lowbyte4; highbyte1; highbyte2; highbyte3; highbyte4 [ low = (lowbyte1 << 24) | (lowbyte2 << 16) | (lowbyte3 << 8) | lowbyte4; high = (highbyte1 << 24) | (highbyte2 << 16) | (highbyte3 << 8) | highbyte4; switch_low = low; switch_num = high - low; switch_high = high; in_table_switch = 1; ]
|
||||
|
||||
{
|
||||
_offset :$(SIZE) = 0;
|
||||
idx :$(SIZE) = 0;
|
||||
padding:$(SIZE) = alignmentPad;
|
||||
local _offset :$(SIZE) = 0;
|
||||
local idx :$(SIZE) = 0;
|
||||
local padding:$(SIZE) = alignmentPad;
|
||||
|
||||
pop(idx);
|
||||
if (idx s< low) goto Default;
|
||||
|
@ -2037,7 +2045,6 @@ dotableswitch: Default, low, high is alignmentPad & Default;lowbyte1; lowbyte2;
|
|||
goto [switch_target];
|
||||
}
|
||||
|
||||
|
||||
:tableswitch dotableswitch, instruction is in_table_switch=0 & in_lookup_switch=0 & op=0xaa & alignmentPad=0; dotableswitch; instruction
|
||||
{
|
||||
build dotableswitch;
|
||||
|
@ -2055,18 +2062,6 @@ dotableswitch: Default, low, high is alignmentPad & Default;lowbyte1; lowbyte2;
|
|||
build dotableswitch;
|
||||
}
|
||||
|
||||
# Switch entry that's not the last one.
|
||||
# no pcode def - this construction is just for consuming all of the bytes of a tableswitch instructions
|
||||
# decrements the switch number
|
||||
:^Switch_case Switch_offset, instruction is (in_table_switch=1 & in_lookup_switch=0); Switch_case; Switch_offset; instruction
|
||||
{
|
||||
}
|
||||
|
||||
#Last switch entry. Get out of switch context.
|
||||
:"case" case Switch_offset is (in_table_switch=1 & in_lookup_switch=0 &switch_num=0); Switch_offset [ in_table_switch=0; case=switch_high-switch_num; ]
|
||||
{
|
||||
}
|
||||
|
||||
#wide loads
|
||||
:wide_iload index is (in_table_switch=0 & in_lookup_switch=0 & w_op=0xc415); indexbyte1; indexbyte2 [index = (indexbyte1 << 8) | indexbyte2; ]
|
||||
{
|
||||
|
|
|
@ -113,9 +113,6 @@ public class JvmSwitchAnalyzer extends AbstractJavaAnalyzer {
|
|||
if (!mnenomic.equals(TABLESWITCH_MNEMONIC) && !mnenomic.equals(LOOKUPSWITCH_MNEMONIC)) {
|
||||
continue; //only care about switch instructions
|
||||
}
|
||||
if (instruction.getMnemonicReferences().length > 0) {
|
||||
continue; //analyzer has already handled this instructions
|
||||
}
|
||||
monitor.setMessage("JvmSwitchAnalyzer: " + instruction.getMinAddress());
|
||||
if (instruction.getMnemonicString().equals(TABLESWITCH_MNEMONIC)) {
|
||||
processTableSwitch(program, reader, instruction, monitor);
|
||||
|
@ -182,13 +179,14 @@ public class JvmSwitchAnalyzer extends AbstractJavaAnalyzer {
|
|||
// WARNING: this is very dependent on the sub-constructor for the switch stmt.
|
||||
// if the op-object order changes for the operand, this will fail
|
||||
Object[] opObjects = instruction.getOpObjects(0);
|
||||
long defaultOffset = ((Scalar) opObjects[0]).getUnsignedValue();
|
||||
long numberOfCases = ((Scalar) opObjects[1]).getUnsignedValue();
|
||||
|
||||
List<Address> addressesToDisassemble = new ArrayList<>();
|
||||
|
||||
//handle the default case
|
||||
Address defaultAddress = instruction.getMinAddress().add(defaultOffset);
|
||||
Address defaultAddress = instruction.getAddress()
|
||||
.getAddressSpace()
|
||||
.getAddress(((Scalar) opObjects[0]).getUnsignedValue());
|
||||
addressesToDisassemble.add(defaultAddress);
|
||||
addLabelAndReference(program, instruction, defaultAddress, DEFAULT_CASE_LABEL);
|
||||
|
||||
|
@ -225,8 +223,9 @@ public class JvmSwitchAnalyzer extends AbstractJavaAnalyzer {
|
|||
|
||||
private void addLabelAndReference(Program program, Instruction switchInstruction,
|
||||
Address target, String label) {
|
||||
program.getReferenceManager().addMemoryReference(switchInstruction.getMinAddress(), target,
|
||||
RefType.COMPUTED_JUMP, SourceType.ANALYSIS, CodeUnit.MNEMONIC);
|
||||
program.getReferenceManager()
|
||||
.addMemoryReference(switchInstruction.getMinAddress(), target,
|
||||
RefType.COMPUTED_JUMP, SourceType.ANALYSIS, CodeUnit.MNEMONIC);
|
||||
|
||||
//put switch table cases into namespace for the switch
|
||||
//create namespace if necessary
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue