diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java index ebae3d0006..7072eb9c0a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/processors/InstructionInfoProvider.java @@ -236,7 +236,7 @@ class InstructionInfoProvider extends ComponentProviderAdapter implements Domain if (column == 0) { return ""; } - return "Operand-" + column; + return "Operand-" + (column - 1); } /** diff --git a/Ghidra/Processors/JVM/data/languages/JVM.ldefs b/Ghidra/Processors/JVM/data/languages/JVM.ldefs index 03cd43c71a..f26094748f 100644 --- a/Ghidra/Processors/JVM/data/languages/JVM.ldefs +++ b/Ghidra/Processors/JVM/data/languages/JVM.ldefs @@ -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" diff --git a/Ghidra/Processors/JVM/data/languages/JVM.slaspec b/Ghidra/Processors/JVM/data/languages/JVM.slaspec index 43c46e7517..25dcdfdfdd 100644 --- a/Ghidra/Processors/JVM/data/languages/JVM.slaspec +++ b/Ghidra/Processors/JVM/data/languages/JVM.slaspec @@ -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; ] { diff --git a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JvmSwitchAnalyzer.java b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JvmSwitchAnalyzer.java index 5cd93af2d5..902e7bede4 100644 --- a/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JvmSwitchAnalyzer.java +++ b/Ghidra/Processors/JVM/src/main/java/ghidra/javaclass/analyzers/JvmSwitchAnalyzer.java @@ -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
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