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) {
|
if (column == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return "Operand-" + column;
|
return "Operand-" + (column - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
endian="big"
|
endian="big"
|
||||||
size="32"
|
size="32"
|
||||||
variant="default"
|
variant="default"
|
||||||
version="1.0"
|
version="1.1"
|
||||||
slafile="JVM.sla"
|
slafile="JVM.sla"
|
||||||
processorspec="JVM.pspec"
|
processorspec="JVM.pspec"
|
||||||
manualindexfile="../manuals/JVM.idx"
|
manualindexfile="../manuals/JVM.idx"
|
||||||
|
|
|
@ -1721,19 +1721,18 @@ Default:"default" addr is defaultbyte1; defaultbyte2; defaultbyte3; defaultbyte4
|
||||||
# lookupswitch
|
# 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
|
#leave the switch statement
|
||||||
{
|
:""LookupSwitch_match is (in_lookup_switch=1 & switch_num=1 & in_table_switch=0); LookupSwitch_match [in_lookup_switch=0;]
|
||||||
}
|
|
||||||
|
|
||||||
:"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; ]
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 = 1 & padVal & op ; pad1 { export *[const]:1 padVal; }
|
||||||
padSwitch: "" is alignmentPad = 0 & padVal & op { 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;
|
local _padding:1 = alignmentPad;
|
||||||
_opcodeAddr:$(SIZE) = inst_start;
|
local _opcodeAddr:$(SIZE) = inst_start;
|
||||||
_defaultAddr:$(SIZE) = inst_start + _default;
|
local _key:$(SIZE) = 0;
|
||||||
_key:$(SIZE) = 0;
|
|
||||||
pop(_key);
|
pop(_key);
|
||||||
_address:$(SIZE) = switchAssist(_key,_opcodeAddr,_padding,_defaultAddr,npairs:$(SIZE));
|
local _address:$(SIZE) = switchAssist(_key,_opcodeAddr,_padding,_default:$(SIZE),npairs:$(SIZE));
|
||||||
goto [ _address ];
|
goto [ _address ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2013,20 +2012,29 @@ _value :$(DOUBLE_SIZE) = 0;
|
||||||
# tableswitch
|
# 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_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; ]
|
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;
|
local _offset :$(SIZE) = 0;
|
||||||
idx :$(SIZE) = 0;
|
local idx :$(SIZE) = 0;
|
||||||
padding:$(SIZE) = alignmentPad;
|
local padding:$(SIZE) = alignmentPad;
|
||||||
|
|
||||||
pop(idx);
|
pop(idx);
|
||||||
if (idx s< low) goto Default;
|
if (idx s< low) goto Default;
|
||||||
|
@ -2037,7 +2045,6 @@ dotableswitch: Default, low, high is alignmentPad & Default;lowbyte1; lowbyte2;
|
||||||
goto [switch_target];
|
goto [switch_target];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
:tableswitch dotableswitch, instruction is in_table_switch=0 & in_lookup_switch=0 & op=0xaa & alignmentPad=0; dotableswitch; instruction
|
:tableswitch dotableswitch, instruction is in_table_switch=0 & in_lookup_switch=0 & op=0xaa & alignmentPad=0; dotableswitch; instruction
|
||||||
{
|
{
|
||||||
build dotableswitch;
|
build dotableswitch;
|
||||||
|
@ -2055,18 +2062,6 @@ dotableswitch: Default, low, high is alignmentPad & Default;lowbyte1; lowbyte2;
|
||||||
build dotableswitch;
|
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 loads
|
||||||
:wide_iload index is (in_table_switch=0 & in_lookup_switch=0 & w_op=0xc415); indexbyte1; indexbyte2 [index = (indexbyte1 << 8) | indexbyte2; ]
|
: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)) {
|
if (!mnenomic.equals(TABLESWITCH_MNEMONIC) && !mnenomic.equals(LOOKUPSWITCH_MNEMONIC)) {
|
||||||
continue; //only care about switch instructions
|
continue; //only care about switch instructions
|
||||||
}
|
}
|
||||||
if (instruction.getMnemonicReferences().length > 0) {
|
|
||||||
continue; //analyzer has already handled this instructions
|
|
||||||
}
|
|
||||||
monitor.setMessage("JvmSwitchAnalyzer: " + instruction.getMinAddress());
|
monitor.setMessage("JvmSwitchAnalyzer: " + instruction.getMinAddress());
|
||||||
if (instruction.getMnemonicString().equals(TABLESWITCH_MNEMONIC)) {
|
if (instruction.getMnemonicString().equals(TABLESWITCH_MNEMONIC)) {
|
||||||
processTableSwitch(program, reader, instruction, monitor);
|
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.
|
// 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
|
// if the op-object order changes for the operand, this will fail
|
||||||
Object[] opObjects = instruction.getOpObjects(0);
|
Object[] opObjects = instruction.getOpObjects(0);
|
||||||
long defaultOffset = ((Scalar) opObjects[0]).getUnsignedValue();
|
|
||||||
long numberOfCases = ((Scalar) opObjects[1]).getUnsignedValue();
|
long numberOfCases = ((Scalar) opObjects[1]).getUnsignedValue();
|
||||||
|
|
||||||
List<Address> addressesToDisassemble = new ArrayList<>();
|
List<Address> addressesToDisassemble = new ArrayList<>();
|
||||||
|
|
||||||
//handle the default case
|
//handle the default case
|
||||||
Address defaultAddress = instruction.getMinAddress().add(defaultOffset);
|
Address defaultAddress = instruction.getAddress()
|
||||||
|
.getAddressSpace()
|
||||||
|
.getAddress(((Scalar) opObjects[0]).getUnsignedValue());
|
||||||
addressesToDisassemble.add(defaultAddress);
|
addressesToDisassemble.add(defaultAddress);
|
||||||
addLabelAndReference(program, instruction, defaultAddress, DEFAULT_CASE_LABEL);
|
addLabelAndReference(program, instruction, defaultAddress, DEFAULT_CASE_LABEL);
|
||||||
|
|
||||||
|
@ -225,8 +223,9 @@ public class JvmSwitchAnalyzer extends AbstractJavaAnalyzer {
|
||||||
|
|
||||||
private void addLabelAndReference(Program program, Instruction switchInstruction,
|
private void addLabelAndReference(Program program, Instruction switchInstruction,
|
||||||
Address target, String label) {
|
Address target, String label) {
|
||||||
program.getReferenceManager().addMemoryReference(switchInstruction.getMinAddress(), target,
|
program.getReferenceManager()
|
||||||
RefType.COMPUTED_JUMP, SourceType.ANALYSIS, CodeUnit.MNEMONIC);
|
.addMemoryReference(switchInstruction.getMinAddress(), target,
|
||||||
|
RefType.COMPUTED_JUMP, SourceType.ANALYSIS, CodeUnit.MNEMONIC);
|
||||||
|
|
||||||
//put switch table cases into namespace for the switch
|
//put switch table cases into namespace for the switch
|
||||||
//create namespace if necessary
|
//create namespace if necessary
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue