classfile_parser/code_attribute/
parser.rs

1use code_attribute::types::Instruction;
2use nom::{
3    bytes::complete::{tag, take},
4    combinator::{complete, fail, map, success},
5    multi::{count, many0},
6    number::complete::{be_i16, be_i32, be_i8, be_u16, be_u32, be_u8},
7    sequence::{pair, preceded, tuple},
8    IResult, Offset,
9};
10
11fn offset<'a>(remaining: &'a [u8], input: &[u8]) -> IResult<&'a [u8], usize> {
12    Ok((remaining, input.offset(remaining)))
13}
14
15fn align(address: usize) -> impl Fn(&[u8]) -> IResult<&[u8], &[u8]> {
16    move |input: &[u8]| take((4 - address % 4) % 4)(input)
17}
18
19fn lookupswitch_parser(input: &[u8]) -> IResult<&[u8], Instruction> {
20    // This function provides type annotations required by rustc.
21    fn each_pair(input: &[u8]) -> IResult<&[u8], (i32, i32)> {
22        let (input, lookup) = be_i32(input)?;
23        let (input, offset) = be_i32(input)?;
24        Ok((input, (lookup, offset)))
25    }
26    let (input, default) = be_i32(input)?;
27    let (input, npairs) = be_u32(input)?;
28    let (input, pairs) = count(each_pair, npairs as usize)(input)?;
29    Ok((input, Instruction::Lookupswitch { default, pairs }))
30}
31
32fn tableswitch_parser(input: &[u8]) -> IResult<&[u8], Instruction> {
33    let (input, default) = be_i32(input)?;
34    let (input, low) = be_i32(input)?;
35    let (input, high) = be_i32(input)?;
36    let (input, offsets) = count(be_i32, (high - low + 1) as usize)(input)?;
37    Ok((
38        input,
39        Instruction::Tableswitch {
40            default,
41            low,
42            high,
43            offsets,
44        },
45    ))
46}
47
48pub fn code_parser(outer_input: &[u8]) -> IResult<&[u8], Vec<(usize, Instruction)>> {
49    many0(complete(|input| {
50        let (input, address) = offset(input, outer_input)?;
51        let (input, instruction) = instruction_parser(input, address)?;
52        Ok((input, (address, instruction)))
53    }))(outer_input)
54}
55
56pub fn instruction_parser(input: &[u8], address: usize) -> IResult<&[u8], Instruction> {
57    let (input, b0) = be_u8(input)?;
58    let (input, instruction) = match b0 {
59        0x32 => success(Instruction::Aaload)(input)?,
60        0x53 => success(Instruction::Aastore)(input)?,
61        0x01 => success(Instruction::Aconstnull)(input)?,
62        0x19 => map(be_u8, Instruction::Aload)(input)?,
63        0x2a => success(Instruction::Aload0)(input)?,
64        0x2b => success(Instruction::Aload1)(input)?,
65        0x2c => success(Instruction::Aload2)(input)?,
66        0x2d => success(Instruction::Aload3)(input)?,
67        0xbd => map(be_u16, Instruction::Anewarray)(input)?,
68        0xb0 => success(Instruction::Areturn)(input)?,
69        0xbe => success(Instruction::Arraylength)(input)?,
70        0x3a => map(be_u8, Instruction::Astore)(input)?,
71        0x4b => success(Instruction::Astore0)(input)?,
72        0x4c => success(Instruction::Astore1)(input)?,
73        0x4d => success(Instruction::Astore2)(input)?,
74        0x4e => success(Instruction::Astore3)(input)?,
75        0xbf => success(Instruction::Athrow)(input)?,
76        0x33 => success(Instruction::Baload)(input)?,
77        0x54 => success(Instruction::Bastore)(input)?,
78        0x10 => map(be_i8, Instruction::Bipush)(input)?,
79        0x34 => success(Instruction::Caload)(input)?,
80        0x55 => success(Instruction::Castore)(input)?,
81        0xc0 => map(be_u16, Instruction::Checkcast)(input)?,
82        0x90 => success(Instruction::D2f)(input)?,
83        0x8e => success(Instruction::D2i)(input)?,
84        0x8f => success(Instruction::D2l)(input)?,
85        0x63 => success(Instruction::Dadd)(input)?,
86        0x31 => success(Instruction::Daload)(input)?,
87        0x52 => success(Instruction::Dastore)(input)?,
88        0x98 => success(Instruction::Dcmpg)(input)?,
89        0x97 => success(Instruction::Dcmpl)(input)?,
90        0x0e => success(Instruction::Dconst0)(input)?,
91        0x0f => success(Instruction::Dconst1)(input)?,
92        0x6f => success(Instruction::Ddiv)(input)?,
93        0x18 => map(be_u8, Instruction::Dload)(input)?,
94        0x26 => success(Instruction::Dload0)(input)?,
95        0x27 => success(Instruction::Dload1)(input)?,
96        0x28 => success(Instruction::Dload2)(input)?,
97        0x29 => success(Instruction::Dload3)(input)?,
98        0x6b => success(Instruction::Dmul)(input)?,
99        0x77 => success(Instruction::Dneg)(input)?,
100        0x73 => success(Instruction::Drem)(input)?,
101        0xaf => success(Instruction::Dreturn)(input)?,
102        0x39 => map(be_u8, Instruction::Dstore)(input)?,
103        0x47 => success(Instruction::Dstore0)(input)?,
104        0x48 => success(Instruction::Dstore1)(input)?,
105        0x49 => success(Instruction::Dstore2)(input)?,
106        0x4a => success(Instruction::Dstore3)(input)?,
107        0x67 => success(Instruction::Dsub)(input)?,
108        0x59 => success(Instruction::Dup)(input)?,
109        0x5a => success(Instruction::Dupx1)(input)?,
110        0x5b => success(Instruction::Dupx2)(input)?,
111        0x5c => success(Instruction::Dup2)(input)?,
112        0x5d => success(Instruction::Dup2x1)(input)?,
113        0x5e => success(Instruction::Dup2x2)(input)?,
114        0x8d => success(Instruction::F2d)(input)?,
115        0x8b => success(Instruction::F2i)(input)?,
116        0x8c => success(Instruction::F2l)(input)?,
117        0x62 => success(Instruction::Fadd)(input)?,
118        0x30 => success(Instruction::Faload)(input)?,
119        0x51 => success(Instruction::Fastore)(input)?,
120        0x96 => success(Instruction::Fcmpg)(input)?,
121        0x95 => success(Instruction::Fcmpl)(input)?,
122        0x0b => success(Instruction::Fconst0)(input)?,
123        0x0c => success(Instruction::Fconst1)(input)?,
124        0x0d => success(Instruction::Fconst2)(input)?,
125        0x6e => success(Instruction::Fdiv)(input)?,
126        0x17 => map(be_u8, Instruction::Fload)(input)?,
127        0x22 => success(Instruction::Fload0)(input)?,
128        0x23 => success(Instruction::Fload1)(input)?,
129        0x24 => success(Instruction::Fload2)(input)?,
130        0x25 => success(Instruction::Fload3)(input)?,
131        0x6a => success(Instruction::Fmul)(input)?,
132        0x76 => success(Instruction::Fneg)(input)?,
133        0x72 => success(Instruction::Frem)(input)?,
134        0xae => success(Instruction::Freturn)(input)?,
135        0x38 => map(be_u8, Instruction::Fstore)(input)?,
136        0x43 => success(Instruction::Fstore0)(input)?,
137        0x44 => success(Instruction::Fstore1)(input)?,
138        0x45 => success(Instruction::Fstore2)(input)?,
139        0x46 => success(Instruction::Fstore3)(input)?,
140        0x66 => success(Instruction::Fsub)(input)?,
141        0xb4 => map(be_u16, Instruction::Getfield)(input)?,
142        0xb2 => map(be_u16, Instruction::Getstatic)(input)?,
143        0xa7 => map(be_i16, Instruction::Goto)(input)?,
144        0xc8 => map(be_i32, Instruction::GotoW)(input)?,
145        0x91 => success(Instruction::I2b)(input)?,
146        0x92 => success(Instruction::I2c)(input)?,
147        0x87 => success(Instruction::I2d)(input)?,
148        0x86 => success(Instruction::I2f)(input)?,
149        0x85 => success(Instruction::I2l)(input)?,
150        0x93 => success(Instruction::I2s)(input)?,
151        0x60 => success(Instruction::Iadd)(input)?,
152        0x2e => success(Instruction::Iaload)(input)?,
153        0x7e => success(Instruction::Iand)(input)?,
154        0x4f => success(Instruction::Iastore)(input)?,
155        0x02 => success(Instruction::Iconstm1)(input)?,
156        0x03 => success(Instruction::Iconst0)(input)?,
157        0x04 => success(Instruction::Iconst1)(input)?,
158        0x05 => success(Instruction::Iconst2)(input)?,
159        0x06 => success(Instruction::Iconst3)(input)?,
160        0x07 => success(Instruction::Iconst4)(input)?,
161        0x08 => success(Instruction::Iconst5)(input)?,
162        0x6c => success(Instruction::Idiv)(input)?,
163        0xa5 => map(be_i16, Instruction::IfAcmpeq)(input)?,
164        0xa6 => map(be_i16, Instruction::IfAcmpne)(input)?,
165        0x9f => map(be_i16, Instruction::IfIcmpeq)(input)?,
166        0xa0 => map(be_i16, Instruction::IfIcmpne)(input)?,
167        0xa1 => map(be_i16, Instruction::IfIcmplt)(input)?,
168        0xa2 => map(be_i16, Instruction::IfIcmpge)(input)?,
169        0xa3 => map(be_i16, Instruction::IfIcmpgt)(input)?,
170        0xa4 => map(be_i16, Instruction::IfIcmple)(input)?,
171        0x99 => map(be_i16, Instruction::Ifeq)(input)?,
172        0x9a => map(be_i16, Instruction::Ifne)(input)?,
173        0x9b => map(be_i16, Instruction::Iflt)(input)?,
174        0x9c => map(be_i16, Instruction::Ifge)(input)?,
175        0x9d => map(be_i16, Instruction::Ifgt)(input)?,
176        0x9e => map(be_i16, Instruction::Ifle)(input)?,
177        0xc7 => map(be_i16, Instruction::Ifnonnull)(input)?,
178        0xc6 => map(be_i16, Instruction::Ifnull)(input)?,
179        0x84 => map(pair(be_u8, be_i8), |(index, value)| Instruction::Iinc {
180            index,
181            value,
182        })(input)?,
183        0x15 => map(be_u8, Instruction::Iload)(input)?,
184        0x1a => success(Instruction::Iload0)(input)?,
185        0x1b => success(Instruction::Iload1)(input)?,
186        0x1c => success(Instruction::Iload2)(input)?,
187        0x1d => success(Instruction::Iload3)(input)?,
188        0x68 => success(Instruction::Imul)(input)?,
189        0x74 => success(Instruction::Ineg)(input)?,
190        0xc1 => map(be_u16, Instruction::Instanceof)(input)?,
191        0xba => map(pair(be_u16, tag(&[0, 0])), |(index, _)| {
192            Instruction::Invokedynamic(index)
193        })(input)?,
194        0xb9 => map(tuple((be_u16, be_u8, tag(&[0]))), |(index, count, _)| {
195            Instruction::Invokeinterface { index, count }
196        })(input)?,
197        0xb7 => map(be_u16, Instruction::Invokespecial)(input)?,
198        0xb8 => map(be_u16, Instruction::Invokestatic)(input)?,
199        0xb6 => map(be_u16, Instruction::Invokevirtual)(input)?,
200        0x80 => success(Instruction::Ior)(input)?,
201        0x70 => success(Instruction::Irem)(input)?,
202        0xac => success(Instruction::Ireturn)(input)?,
203        0x78 => success(Instruction::Ishl)(input)?,
204        0x7a => success(Instruction::Ishr)(input)?,
205        0x36 => map(be_u8, Instruction::Istore)(input)?,
206        0x3b => success(Instruction::Istore0)(input)?,
207        0x3c => success(Instruction::Istore1)(input)?,
208        0x3d => success(Instruction::Istore2)(input)?,
209        0x3e => success(Instruction::Istore3)(input)?,
210        0x64 => success(Instruction::Isub)(input)?,
211        0x7c => success(Instruction::Iushr)(input)?,
212        0x82 => success(Instruction::Ixor)(input)?,
213        0xa8 => map(be_i16, Instruction::Jsr)(input)?,
214        0xc9 => map(be_i32, Instruction::JsrW)(input)?,
215        0x8a => success(Instruction::L2d)(input)?,
216        0x89 => success(Instruction::L2f)(input)?,
217        0x88 => success(Instruction::L2i)(input)?,
218        0x61 => success(Instruction::Ladd)(input)?,
219        0x2f => success(Instruction::Laload)(input)?,
220        0x7f => success(Instruction::Land)(input)?,
221        0x50 => success(Instruction::Lastore)(input)?,
222        0x94 => success(Instruction::Lcmp)(input)?,
223        0x09 => success(Instruction::Lconst0)(input)?,
224        0x0a => success(Instruction::Lconst1)(input)?,
225        0x12 => map(be_u8, Instruction::Ldc)(input)?,
226        0x13 => map(be_u16, Instruction::LdcW)(input)?,
227        0x14 => map(be_u16, Instruction::Ldc2W)(input)?,
228        0x6d => success(Instruction::Ldiv)(input)?,
229        0x16 => map(be_u8, Instruction::Lload)(input)?,
230        0x1e => success(Instruction::Lload0)(input)?,
231        0x1f => success(Instruction::Lload1)(input)?,
232        0x20 => success(Instruction::Lload2)(input)?,
233        0x21 => success(Instruction::Lload3)(input)?,
234        0x69 => success(Instruction::Lmul)(input)?,
235        0x75 => success(Instruction::Lneg)(input)?,
236        0xab => preceded(align(address + 1), lookupswitch_parser)(input)?,
237        0x81 => success(Instruction::Lor)(input)?,
238        0x71 => success(Instruction::Lrem)(input)?,
239        0xad => success(Instruction::Lreturn)(input)?,
240        0x79 => success(Instruction::Lshl)(input)?,
241        0x7b => success(Instruction::Lshr)(input)?,
242        0x37 => map(be_u8, Instruction::Lstore)(input)?,
243        0x3f => success(Instruction::Lstore0)(input)?,
244        0x40 => success(Instruction::Lstore1)(input)?,
245        0x41 => success(Instruction::Lstore2)(input)?,
246        0x42 => success(Instruction::Lstore3)(input)?,
247        0x65 => success(Instruction::Lsub)(input)?,
248        0x7d => success(Instruction::Lushr)(input)?,
249        0x83 => success(Instruction::Lxor)(input)?,
250        0xc2 => success(Instruction::Monitorenter)(input)?,
251        0xc3 => success(Instruction::Monitorexit)(input)?,
252        0xc5 => map(pair(be_u16, be_u8), |(index, dimensions)| {
253            Instruction::Multianewarray { index, dimensions }
254        })(input)?,
255        0xbb => map(be_u16, Instruction::New)(input)?,
256        0xbc => map(be_u8, Instruction::Newarray)(input)?,
257        0x00 => success(Instruction::Nop)(input)?,
258        0x57 => success(Instruction::Pop)(input)?,
259        0x58 => success(Instruction::Pop2)(input)?,
260        0xb5 => map(be_u16, Instruction::Putfield)(input)?,
261        0xb3 => map(be_u16, Instruction::Putstatic)(input)?,
262        0xa9 => map(be_u8, Instruction::Ret)(input)?,
263        0xb1 => success(Instruction::Return)(input)?,
264        0x35 => success(Instruction::Saload)(input)?,
265        0x56 => success(Instruction::Sastore)(input)?,
266        0x11 => map(be_i16, Instruction::Sipush)(input)?,
267        0x5f => success(Instruction::Swap)(input)?,
268        0xaa => preceded(align(address + 1), tableswitch_parser)(input)?,
269        0xc4 => {
270            let (input, b1) = be_u8(input)?;
271            match b1 {
272                0x19 => map(be_u16, Instruction::AloadWide)(input)?,
273                0x3a => map(be_u16, Instruction::AstoreWide)(input)?,
274                0x18 => map(be_u16, Instruction::DloadWide)(input)?,
275                0x39 => map(be_u16, Instruction::DstoreWide)(input)?,
276                0x17 => map(be_u16, Instruction::FloadWide)(input)?,
277                0x38 => map(be_u16, Instruction::FstoreWide)(input)?,
278                0x15 => map(be_u16, Instruction::IloadWide)(input)?,
279                0x36 => map(be_u16, Instruction::IstoreWide)(input)?,
280                0x16 => map(be_u16, Instruction::LloadWide)(input)?,
281                0x37 => map(be_u16, Instruction::LstoreWide)(input)?,
282                0xa9 => map(be_u16, Instruction::RetWide)(input)?,
283                0x84 => map(pair(be_u16, be_i16), |(index, value)| {
284                    Instruction::IincWide { index, value }
285                })(input)?,
286                _ => fail(input)?,
287            }
288        }
289        _ => fail(input)?,
290    };
291    Ok((input, instruction))
292}