NationalSecurityAgency / ghidra

Ghidra is a software reverse engineering (SRE) framework
https://www.nsa.gov/ghidra
Apache License 2.0
51.62k stars 5.87k forks source link

Sleigh: | not functioning as or in bit pattern #1213

Open astrelsky opened 5 years ago

astrelsky commented 5 years ago

Describe the bug Using | in a sleigh bit pattern requires that both tables match for the entire pattern to match.

To Reproduce Steps to reproduce the behavior:

  1. See Additional context

Expected behavior | to match the pattern if at least one of the tables match.

Environment (please complete the following information):

Additional context Here is the sleigh declaration:

:vftoi4^dest vuft, vufs   is (vuinst | VUFLAGS) & dest & vuft & vufs & vuop_0_10=0b00101111101
{
    vuft = VFTOI(dest, vufs);
}

Additional Table declarations incase they are needed for reference:

vuinst: is prime=18 & vuco=1 & microMode=0 { export 0:1; }

with : microMode=1 & vuco=0 & vuco1=0 {
    with V1E: {
        : " [E]" is vucE=1 [cE=1; globalset(inst_next, cE);] { delayslot(2); return [0:4]; }
        : is vucE=0 {}
    }
    with V1M: {
        : " [M]" is vucM=1 [ cM = 1; globalset(inst_start, cM); ] {}
        : is vucM=0 {}
    }
    with V1D: {
        : " [D]" is vucD=1 { trap(); }
        : is vucD=0 {}
    }
    with V1T: {
        : " [T]" is vucT=1 { trap(); }
        : is vucT=0 {}
    }
}

with : microMode=1 & vuMicro=0 & cUpper=0 {
    with V1E_L: {
        :" [E]" is vucE_L=1 [cE=1; globalset(inst_next, cE);] { delayslot(1); return [0:4]; }
        : is vucE_L=0 {}
    }
    with V1M_L: {
        : " [M]" is vucM_L=1 [ cM = 1; globalset(inst_start, cM); ] {}
        : is vucM_L=0 {}
    }
    with V1D_L: {
        : " [D]" is vucD_L=1 { trap(); }
        : is vucD_L=0 {}
    }
    with V1T_L: {
        : " [T]" is vucT_L=1 { trap(); }
        : is vucT_L=0 {}
    }
}

VUFLAGS:^V1E^V1M^V1D^V1T is cUpper=1 & V1E & V1M & V1D & V1T [cUpper=0; globalset(inst_next, cUpper);] { build V1D; build V1T; }
VUFLAGS_L:^V1E_L^V1M_L^V1D_L^V1T_L is V1E_L & V1M_L & V1D_L & V1T_L { build V1D_L; build V1T_L; }

Here is the debug instruction parse output of the instruction that should match.

check pattern[1 of 1]: {line# 331} vftoi4<dest> <vuft>, <vufs>
   (  byte pattern: mask=11111111.00000111.00000000.11111110
              bytes[0-3]=01111101.00100001.11100101.01001011
             match-value=01111101.00000001.00000000.01001010 Matched
   ) -and- (
      context pattern: mask=10000000.00000000.00000000.00000000
             context(0..31)=00000000.00000000.00000000.00000000
                match-value=00000000.00000000.00000000.00000000 Matched
                  microMode(0,0) == 0x0 Match
   ) Matched
vuinst: resolving...
   check pattern[1 of 1] vuinst: {line# 163} 
      (  byte pattern: mask=11111110.00000000.00000000.00000000
                 bytes[3-6]=01001011.00001000.00000000.11100000
                match-value=01001010.00000000.00000000.00000000 Matched
      ) -and- (
         context pattern: mask=10000000.00000000.00000000.00000000
                context(0..31)=00000000.00000000.00000000.00000000
                   match-value=00000000.00000000.00000000.00000000 Matched
                     microMode(0,0) == 0x0 Match
      ) Matched
VUFLAGS: resolving...
   check pattern[1 of 1] VUFLAGS: {line# 203} <V1E><V1M><V1D><V1T>
      (  byte pattern: mask=00000110.00000000.00000000.00000000
                 bytes[3-6]=01001011.00001000.00000000.11100000
                match-value=00000000.00000000.00000000.00000000 Failed
      ) -and- (
         context pattern: mask=10010000.00000000.00000000.00000000
                context(0..31)=00000000.00000000.00000000.00000000
                   match-value=10010000.00000000.00000000.00000000 Failed
                     cUpper(3,3) == 0x1 Failed (=0x0)
                     microMode(0,0) == 0x1 Failed (=0x0)
      ) Failed
   Unable to resolve constructor

I would also like to mention that replacing (vuinst | VUFLAGS) with say UPPER and declaring UPPER as the following results in running out of heap memory when compiling.

VUPPER:^VUFLAGS is VUFLAGS { build VUFLAGS; }
VUPPER: is vuinst {}
emteere commented 4 years ago

I would not do sub-constructor matches with an "|". Seems rather confusing too. You have actions and context on both sub-constructors, what if it matches both, add the pcode and actions for both? Not even sure that works (as you mention ;-) ) This shouldn't be allowed in sleigh, but everything can't be caught. I suppose the SleighEditor in eclipse could catch it and make it an error.

Split the base constructor into two with VUFLAGS in one and vuinst in the other.

astrelsky commented 4 years ago

I would not do sub-constructor matches with an "|". Seems rather confusing too. You have actions and context on both sub-constructors, what if it matches both, add the pcode and actions for both? Not even sure that works (as you mention ;-) ) This shouldn't be allowed in sleigh, but everything can't be caught. I suppose the SleighEditor in eclipse could catch it and make it an error.

Split the base constructor into two with VUFLAGS in one and vuinst in the other.

They can't both match, it's impossible. microMode is a context register. VUFLAGS requires microMode=1 while vuinst requires microMode=0.

The only real difference between the two is that when microMode=1 flag registers are set for cop2 which also gets reflected at the end of the mnemonic and when microMode=0 the prime bits are fixed, vuco=1 and 'v' is a prefix of the instruction.

I currently have them split up its just a lot of duplication.