Skip to main content

rust_asm/
class_reader.rs

1use std::fmt;
2
3use crate::insn::{
4    AbstractInsnNode, FieldInsnNode, IincInsnNode, Insn, InsnNode, IntInsnNode,
5    InvokeDynamicInsnNode, InvokeInterfaceInsnNode, JumpInsnNode, LabelNode, LdcInsnNode, LdcValue,
6    LookupSwitchInsnNode, MemberRef, MethodInsnNode, MultiANewArrayInsnNode, TableSwitchInsnNode,
7    TryCatchBlockNode, TypeInsnNode, VarInsnNode,
8};
9
10#[derive(Debug)]
11pub enum ClassReadError {
12    UnexpectedEof,
13    InvalidMagic(u32),
14    InvalidConstantPoolTag(u8),
15    InvalidIndex(u16),
16    InvalidAttribute(String),
17    InvalidOpcode { opcode: u8, offset: usize },
18    Utf8Error(String),
19}
20
21impl fmt::Display for ClassReadError {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            ClassReadError::UnexpectedEof => write!(f, "unexpected end of input"),
25            ClassReadError::InvalidMagic(magic) => write!(f, "invalid magic 0x{magic:08x}"),
26            ClassReadError::InvalidConstantPoolTag(tag) => {
27                write!(f, "invalid constant pool tag {tag}")
28            }
29            ClassReadError::InvalidIndex(index) => write!(f, "invalid constant pool index {index}"),
30            ClassReadError::InvalidAttribute(name) => write!(f, "invalid attribute {name}"),
31            ClassReadError::InvalidOpcode { opcode, offset } => {
32                write!(f, "invalid opcode 0x{opcode:02x} at {offset}")
33            }
34            ClassReadError::Utf8Error(msg) => write!(f, "modified utf8 error: {msg}"),
35        }
36    }
37}
38
39impl std::error::Error for ClassReadError {}
40
41#[derive(Debug, Clone)]
42pub enum LdcConstant {
43    Integer(i32),
44    Float(f32),
45    Long(i64),
46    Double(f64),
47    String(String),
48    Class(String),
49    MethodType(String),
50    MethodHandle {
51        reference_kind: u8,
52        reference_index: u16,
53    },
54    Dynamic,
55}
56
57pub trait FieldVisitor {
58    fn visit_end(&mut self) {}
59}
60
61pub trait MethodVisitor {
62    fn visit_code(&mut self) {}
63    fn visit_insn(&mut self, _opcode: u8) {}
64    fn visit_int_insn(&mut self, _opcode: u8, _operand: i32) {}
65    fn visit_var_insn(&mut self, _opcode: u8, _var_index: u16) {}
66    fn visit_type_insn(&mut self, _opcode: u8, _type_name: &str) {}
67    fn visit_field_insn(&mut self, _opcode: u8, _owner: &str, _name: &str, _desc: &str) {}
68    fn visit_method_insn(
69        &mut self,
70        _opcode: u8,
71        _owner: &str,
72        _name: &str,
73        _desc: &str,
74        _is_interface: bool,
75    ) {
76    }
77    fn visit_invoke_dynamic_insn(&mut self, _name: &str, _desc: &str) {}
78    fn visit_jump_insn(&mut self, _opcode: u8, _target_offset: i32) {}
79    fn visit_ldc_insn(&mut self, _value: LdcConstant) {}
80    fn visit_iinc_insn(&mut self, _var_index: u16, _increment: i16) {}
81    fn visit_table_switch(&mut self, _default: i32, _low: i32, _high: i32, _targets: &[i32]) {}
82    fn visit_lookup_switch(&mut self, _default: i32, _pairs: &[(i32, i32)]) {}
83    fn visit_multi_anewarray_insn(&mut self, _type_name: &str, _dims: u8) {}
84    fn visit_maxs(&mut self, _max_stack: u16, _max_locals: u16) {}
85    fn visit_end(&mut self) {}
86}
87
88pub trait ClassVisitor {
89    fn visit(
90        &mut self,
91        _major: u16,
92        _minor: u16,
93        _access_flags: u16,
94        _name: &str,
95        _super_name: Option<&str>,
96        _interfaces: &[String],
97    ) {
98    }
99    fn visit_source(&mut self, _source: &str) {}
100    fn visit_field(
101        &mut self,
102        _access_flags: u16,
103        _name: &str,
104        _descriptor: &str,
105    ) -> Option<Box<dyn FieldVisitor>> {
106        None
107    }
108    fn visit_method(
109        &mut self,
110        _access_flags: u16,
111        _name: &str,
112        _descriptor: &str,
113    ) -> Option<Box<dyn MethodVisitor>> {
114        None
115    }
116    fn visit_end(&mut self) {}
117}
118
119pub struct ClassReader {
120    bytes: Vec<u8>,
121}
122
123impl ClassReader {
124    pub fn new(bytes: &[u8]) -> Self {
125        Self {
126            bytes: bytes.to_vec(),
127        }
128    }
129
130    pub fn accept(
131        &self,
132        visitor: &mut dyn ClassVisitor,
133        _options: u32,
134    ) -> Result<(), ClassReadError> {
135        let class_file = read_class_file(&self.bytes)?;
136        let name = class_file.class_name(class_file.this_class)?.to_string();
137        let super_name = if class_file.super_class == 0 {
138            None
139        } else {
140            Some(class_file.class_name(class_file.super_class)?.to_string())
141        };
142        let mut interfaces = Vec::with_capacity(class_file.interfaces.len());
143        for index in &class_file.interfaces {
144            interfaces.push(class_file.class_name(*index)?.to_string());
145        }
146
147        visitor.visit(
148            class_file.major_version,
149            class_file.minor_version,
150            class_file.access_flags,
151            &name,
152            super_name.as_deref(),
153            &interfaces,
154        );
155
156        for attr in &class_file.attributes {
157            if let AttributeInfo::SourceFile { sourcefile_index } = attr {
158                let source = class_file.cp_utf8(*sourcefile_index)?;
159                visitor.visit_source(source);
160            }
161        }
162
163        for field in &class_file.fields {
164            let field_name = class_file.cp_utf8(field.name_index)?;
165            let field_desc = class_file.cp_utf8(field.descriptor_index)?;
166            if let Some(mut fv) = visitor.visit_field(field.access_flags, field_name, field_desc) {
167                fv.visit_end();
168            }
169        }
170
171        for method in &class_file.methods {
172            let method_name = class_file.cp_utf8(method.name_index)?;
173            let method_desc = class_file.cp_utf8(method.descriptor_index)?;
174            if let Some(mut mv) =
175                visitor.visit_method(method.access_flags, method_name, method_desc)
176            {
177                let code = method.attributes.iter().find_map(|attr| match attr {
178                    AttributeInfo::Code(code) => Some(code),
179                    _ => None,
180                });
181                if let Some(code) = code {
182                    mv.visit_code();
183                    let instructions = parse_code_instructions_with_offsets(&code.code)?;
184                    for instruction in instructions {
185                        visit_instruction(
186                            &class_file.constant_pool,
187                            instruction.offset as i32,
188                            instruction.insn,
189                            &mut *mv,
190                        )?;
191                    }
192                    mv.visit_maxs(code.max_stack, code.max_locals);
193                }
194                mv.visit_end();
195            }
196        }
197
198        visitor.visit_end();
199        Ok(())
200    }
201
202    pub fn to_class_node(&self) -> Result<crate::nodes::ClassNode, ClassReadError> {
203        let class_file = read_class_file(&self.bytes)?;
204        class_file.to_class_node()
205    }
206}
207
208#[derive(Debug, Clone)]
209pub enum CpInfo {
210    Unusable,
211    Utf8(String),
212    Integer(i32),
213    Float(f32),
214    Long(i64),
215    Double(f64),
216    Class {
217        name_index: u16,
218    },
219    String {
220        string_index: u16,
221    },
222    Fieldref {
223        class_index: u16,
224        name_and_type_index: u16,
225    },
226    Methodref {
227        class_index: u16,
228        name_and_type_index: u16,
229    },
230    InterfaceMethodref {
231        class_index: u16,
232        name_and_type_index: u16,
233    },
234    NameAndType {
235        name_index: u16,
236        descriptor_index: u16,
237    },
238    MethodHandle {
239        reference_kind: u8,
240        reference_index: u16,
241    },
242    MethodType {
243        descriptor_index: u16,
244    },
245    Dynamic {
246        bootstrap_method_attr_index: u16,
247        name_and_type_index: u16,
248    },
249    InvokeDynamic {
250        bootstrap_method_attr_index: u16,
251        name_and_type_index: u16,
252    },
253    Module {
254        name_index: u16,
255    },
256    Package {
257        name_index: u16,
258    },
259}
260
261#[derive(Debug, Clone)]
262pub struct ClassFile {
263    pub minor_version: u16,
264    pub major_version: u16,
265    pub constant_pool: Vec<CpInfo>,
266    pub access_flags: u16,
267    pub this_class: u16,
268    pub super_class: u16,
269    pub interfaces: Vec<u16>,
270    pub fields: Vec<FieldInfo>,
271    pub methods: Vec<MethodInfo>,
272    pub attributes: Vec<AttributeInfo>,
273}
274
275impl ClassFile {
276    pub fn cp_utf8(&self, index: u16) -> Result<&str, ClassReadError> {
277        match self
278            .constant_pool
279            .get(index as usize)
280            .ok_or(ClassReadError::InvalidIndex(index))?
281        {
282            CpInfo::Utf8(value) => Ok(value.as_str()),
283            _ => Err(ClassReadError::InvalidIndex(index)),
284        }
285    }
286
287    pub fn class_name(&self, index: u16) -> Result<&str, ClassReadError> {
288        match self
289            .constant_pool
290            .get(index as usize)
291            .ok_or(ClassReadError::InvalidIndex(index))?
292        {
293            CpInfo::Class { name_index } => self.cp_utf8(*name_index),
294            _ => Err(ClassReadError::InvalidIndex(index)),
295        }
296    }
297
298    pub fn to_class_node(&self) -> Result<crate::nodes::ClassNode, ClassReadError> {
299        let name = self.class_name(self.this_class)?.to_string();
300        let super_name = if self.super_class == 0 {
301            None
302        } else {
303            Some(self.class_name(self.super_class)?.to_string())
304        };
305        let source_file = self.attributes.iter().find_map(|attr| match attr {
306            AttributeInfo::SourceFile { sourcefile_index } => self
307                .cp_utf8(*sourcefile_index)
308                .ok()
309                .map(|value| value.to_string()),
310            _ => None,
311        });
312        let mut interfaces = Vec::with_capacity(self.interfaces.len());
313        for index in &self.interfaces {
314            interfaces.push(self.class_name(*index)?.to_string());
315        }
316
317        let mut fields = Vec::with_capacity(self.fields.len());
318        for field in &self.fields {
319            let name = self.cp_utf8(field.name_index)?.to_string();
320            let descriptor = self.cp_utf8(field.descriptor_index)?.to_string();
321            fields.push(crate::nodes::FieldNode {
322                access_flags: field.access_flags,
323                name_index: field.name_index,
324                descriptor_index: field.descriptor_index,
325                name,
326                descriptor,
327                attributes: field.attributes.clone(),
328            });
329        }
330
331        let mut methods = Vec::with_capacity(self.methods.len());
332        for method in &self.methods {
333            let name = self.cp_utf8(method.name_index)?.to_string();
334            let descriptor = self.cp_utf8(method.descriptor_index)?.to_string();
335            let code = method.attributes.iter().find_map(|attr| match attr {
336                AttributeInfo::Code(code) => Some(code.clone()),
337                _ => None,
338            });
339            methods.push(crate::nodes::MethodNode {
340                access_flags: method.access_flags,
341                name_index: method.name_index,
342                descriptor_index: method.descriptor_index,
343                name,
344                descriptor,
345                code,
346                attributes: method.attributes.clone(),
347            });
348        }
349
350        Ok(crate::nodes::ClassNode {
351            minor_version: self.minor_version,
352            major_version: self.major_version,
353            access_flags: self.access_flags,
354            constant_pool: self.constant_pool.clone(),
355            this_class: self.this_class,
356            super_class: self.super_class,
357            name,
358            super_name,
359            source_file,
360            interfaces,
361            interface_indices: self.interfaces.clone(),
362            fields,
363            methods,
364            attributes: self.attributes.clone(),
365        })
366    }
367}
368
369#[derive(Debug, Clone)]
370pub struct FieldInfo {
371    pub access_flags: u16,
372    pub name_index: u16,
373    pub descriptor_index: u16,
374    pub attributes: Vec<AttributeInfo>,
375}
376
377#[derive(Debug, Clone)]
378pub struct MethodInfo {
379    pub access_flags: u16,
380    pub name_index: u16,
381    pub descriptor_index: u16,
382    pub attributes: Vec<AttributeInfo>,
383}
384
385#[derive(Debug, Clone)]
386pub enum AttributeInfo {
387    Code(CodeAttribute),
388    ConstantValue { constantvalue_index: u16 },
389    Exceptions { exception_index_table: Vec<u16> },
390    SourceFile { sourcefile_index: u16 },
391    LineNumberTable { entries: Vec<LineNumber> },
392    LocalVariableTable { entries: Vec<LocalVariable> },
393    Signature { signature_index: u16 },
394    StackMapTable { entries: Vec<StackMapFrame> },
395    Deprecated,
396    Synthetic,
397    InnerClasses { classes: Vec<InnerClass> },
398    EnclosingMethod { class_index: u16, method_index: u16 },
399    BootstrapMethods { methods: Vec<BootstrapMethod> },
400    MethodParameters { parameters: Vec<MethodParameter> },
401    Unknown { name: String, info: Vec<u8> },
402}
403
404#[derive(Debug, Clone)]
405pub struct CodeAttribute {
406    pub max_stack: u16,
407    pub max_locals: u16,
408    pub code: Vec<u8>,
409    pub instructions: Vec<Insn>,
410    pub insn_nodes: Vec<AbstractInsnNode>,
411    pub exception_table: Vec<ExceptionTableEntry>,
412    pub try_catch_blocks: Vec<TryCatchBlockNode>,
413    pub attributes: Vec<AttributeInfo>,
414}
415
416#[derive(Debug, Clone)]
417pub struct ExceptionTableEntry {
418    pub start_pc: u16,
419    pub end_pc: u16,
420    pub handler_pc: u16,
421    pub catch_type: u16,
422}
423
424#[derive(Debug, Clone)]
425pub struct LineNumber {
426    pub start_pc: u16,
427    pub line_number: u16,
428}
429
430#[derive(Debug, Clone)]
431pub struct LocalVariable {
432    pub start_pc: u16,
433    pub length: u16,
434    pub name_index: u16,
435    pub descriptor_index: u16,
436    pub index: u16,
437}
438
439#[derive(Debug, Clone)]
440pub struct InnerClass {
441    pub inner_class_info_index: u16,
442    pub outer_class_info_index: u16,
443    pub inner_name_index: u16,
444    pub inner_class_access_flags: u16,
445}
446
447#[derive(Debug, Clone)]
448pub struct BootstrapMethod {
449    pub bootstrap_method_ref: u16,
450    pub bootstrap_arguments: Vec<u16>,
451}
452
453#[derive(Debug, Clone)]
454pub struct MethodParameter {
455    pub name_index: u16,
456    pub access_flags: u16,
457}
458
459#[derive(Debug, Clone, PartialEq, Eq)]
460pub enum VerificationTypeInfo {
461    Top,
462    Integer,
463    Float,
464    Long,
465    Double,
466    Null,
467    UninitializedThis,
468    Object { cpool_index: u16 },
469    Uninitialized { offset: u16 },
470}
471
472#[derive(Debug, Clone)]
473pub enum StackMapFrame {
474    SameFrame {
475        offset_delta: u16,
476    },
477    SameLocals1StackItemFrame {
478        offset_delta: u16,
479        stack: VerificationTypeInfo,
480    },
481    SameLocals1StackItemFrameExtended {
482        offset_delta: u16,
483        stack: VerificationTypeInfo,
484    },
485    ChopFrame {
486        offset_delta: u16,
487        k: u8,
488    },
489    SameFrameExtended {
490        offset_delta: u16,
491    },
492    AppendFrame {
493        offset_delta: u16,
494        locals: Vec<VerificationTypeInfo>,
495    },
496    FullFrame {
497        offset_delta: u16,
498        locals: Vec<VerificationTypeInfo>,
499        stack: Vec<VerificationTypeInfo>,
500    },
501}
502
503pub fn read_class_file(bytes: &[u8]) -> Result<ClassFile, ClassReadError> {
504    let mut reader = ByteReader::new(bytes);
505    let magic = reader.read_u4()?;
506    if magic != 0xCAFEBABE {
507        return Err(ClassReadError::InvalidMagic(magic));
508    }
509    let minor_version = reader.read_u2()?;
510    let major_version = reader.read_u2()?;
511    let constant_pool = read_constant_pool(&mut reader)?;
512    let access_flags = reader.read_u2()?;
513    let this_class = reader.read_u2()?;
514    let super_class = reader.read_u2()?;
515    let interfaces = read_u2_table(&mut reader)?;
516    let fields = read_fields(&mut reader, &constant_pool)?;
517    let methods = read_methods(&mut reader, &constant_pool)?;
518    let attributes = read_attributes(&mut reader, &constant_pool)?;
519
520    Ok(ClassFile {
521        minor_version,
522        major_version,
523        constant_pool,
524        access_flags,
525        this_class,
526        super_class,
527        interfaces,
528        fields,
529        methods,
530        attributes,
531    })
532}
533
534fn read_constant_pool(reader: &mut ByteReader<'_>) -> Result<Vec<CpInfo>, ClassReadError> {
535    let count = reader.read_u2()? as usize;
536    let mut pool = Vec::with_capacity(count);
537    pool.push(CpInfo::Unusable);
538
539    let mut index = 1;
540    while index < count {
541        let tag = reader.read_u1()?;
542        let entry = match tag {
543            1 => {
544                let len = reader.read_u2()? as usize;
545                let bytes = reader.read_bytes(len)?;
546                let value = decode_modified_utf8(&bytes)?;
547                CpInfo::Utf8(value)
548            }
549            3 => {
550                let value = reader.read_u4()? as i32;
551                CpInfo::Integer(value)
552            }
553            4 => {
554                let value = f32::from_bits(reader.read_u4()?);
555                CpInfo::Float(value)
556            }
557            5 => {
558                let value = reader.read_u8()? as i64;
559                CpInfo::Long(value)
560            }
561            6 => {
562                let value = f64::from_bits(reader.read_u8()?);
563                CpInfo::Double(value)
564            }
565            7 => CpInfo::Class {
566                name_index: reader.read_u2()?,
567            },
568            8 => CpInfo::String {
569                string_index: reader.read_u2()?,
570            },
571            9 => CpInfo::Fieldref {
572                class_index: reader.read_u2()?,
573                name_and_type_index: reader.read_u2()?,
574            },
575            10 => CpInfo::Methodref {
576                class_index: reader.read_u2()?,
577                name_and_type_index: reader.read_u2()?,
578            },
579            11 => CpInfo::InterfaceMethodref {
580                class_index: reader.read_u2()?,
581                name_and_type_index: reader.read_u2()?,
582            },
583            12 => CpInfo::NameAndType {
584                name_index: reader.read_u2()?,
585                descriptor_index: reader.read_u2()?,
586            },
587            15 => CpInfo::MethodHandle {
588                reference_kind: reader.read_u1()?,
589                reference_index: reader.read_u2()?,
590            },
591            16 => CpInfo::MethodType {
592                descriptor_index: reader.read_u2()?,
593            },
594            17 => CpInfo::Dynamic {
595                bootstrap_method_attr_index: reader.read_u2()?,
596                name_and_type_index: reader.read_u2()?,
597            },
598            18 => CpInfo::InvokeDynamic {
599                bootstrap_method_attr_index: reader.read_u2()?,
600                name_and_type_index: reader.read_u2()?,
601            },
602            19 => CpInfo::Module {
603                name_index: reader.read_u2()?,
604            },
605            20 => CpInfo::Package {
606                name_index: reader.read_u2()?,
607            },
608            _ => return Err(ClassReadError::InvalidConstantPoolTag(tag)),
609        };
610
611        pool.push(entry);
612
613        if tag == 5 || tag == 6 {
614            pool.push(CpInfo::Unusable);
615            index += 2;
616        } else {
617            index += 1;
618        }
619    }
620
621    Ok(pool)
622}
623
624fn read_u2_table(reader: &mut ByteReader<'_>) -> Result<Vec<u16>, ClassReadError> {
625    let count = reader.read_u2()? as usize;
626    let mut values = Vec::with_capacity(count);
627    for _ in 0..count {
628        values.push(reader.read_u2()?);
629    }
630    Ok(values)
631}
632
633fn read_fields(
634    reader: &mut ByteReader<'_>,
635    cp: &[CpInfo],
636) -> Result<Vec<FieldInfo>, ClassReadError> {
637    let count = reader.read_u2()? as usize;
638    let mut fields = Vec::with_capacity(count);
639    for _ in 0..count {
640        let access_flags = reader.read_u2()?;
641        let name_index = reader.read_u2()?;
642        let descriptor_index = reader.read_u2()?;
643        let attributes = read_attributes(reader, cp)?;
644        fields.push(FieldInfo {
645            access_flags,
646            name_index,
647            descriptor_index,
648            attributes,
649        });
650    }
651    Ok(fields)
652}
653
654fn read_methods(
655    reader: &mut ByteReader<'_>,
656    cp: &[CpInfo],
657) -> Result<Vec<MethodInfo>, ClassReadError> {
658    let count = reader.read_u2()? as usize;
659    let mut methods = Vec::with_capacity(count);
660    for _ in 0..count {
661        let access_flags = reader.read_u2()?;
662        let name_index = reader.read_u2()?;
663        let descriptor_index = reader.read_u2()?;
664        let attributes = read_attributes(reader, cp)?;
665        methods.push(MethodInfo {
666            access_flags,
667            name_index,
668            descriptor_index,
669            attributes,
670        });
671    }
672    Ok(methods)
673}
674
675fn read_attributes(
676    reader: &mut ByteReader<'_>,
677    cp: &[CpInfo],
678) -> Result<Vec<AttributeInfo>, ClassReadError> {
679    let count = reader.read_u2()? as usize;
680    let mut attributes = Vec::with_capacity(count);
681    for _ in 0..count {
682        let name_index = reader.read_u2()?;
683        let length = reader.read_u4()? as usize;
684        let name = cp_utf8(cp, name_index)?;
685        let info = reader.read_bytes(length)?;
686        let attribute = parse_attribute(name, info, cp)?;
687        attributes.push(attribute);
688    }
689    Ok(attributes)
690}
691
692fn parse_attribute(
693    name: &str,
694    info: Vec<u8>,
695    cp: &[CpInfo],
696) -> Result<AttributeInfo, ClassReadError> {
697    let mut reader = ByteReader::new(&info);
698    let attribute = match name {
699        "Code" => {
700            let max_stack = reader.read_u2()?;
701            let max_locals = reader.read_u2()?;
702            let code_length = reader.read_u4()? as usize;
703            let code = reader.read_bytes(code_length)?;
704            let instructions = parse_code_instructions(&code)?;
705            let exception_table_length = reader.read_u2()? as usize;
706            let mut exception_table = Vec::with_capacity(exception_table_length);
707            for _ in 0..exception_table_length {
708                exception_table.push(ExceptionTableEntry {
709                    start_pc: reader.read_u2()?,
710                    end_pc: reader.read_u2()?,
711                    handler_pc: reader.read_u2()?,
712                    catch_type: reader.read_u2()?,
713                });
714            }
715            let attributes = read_attributes(&mut reader, cp)?;
716            let (insn_nodes, try_catch_blocks) = build_insn_nodes(&code, &exception_table, cp)?;
717            AttributeInfo::Code(CodeAttribute {
718                max_stack,
719                max_locals,
720                code,
721                instructions,
722                insn_nodes,
723                exception_table,
724                try_catch_blocks,
725                attributes,
726            })
727        }
728        "ConstantValue" => AttributeInfo::ConstantValue {
729            constantvalue_index: reader.read_u2()?,
730        },
731        "Exceptions" => {
732            let count = reader.read_u2()? as usize;
733            let mut exception_index_table = Vec::with_capacity(count);
734            for _ in 0..count {
735                exception_index_table.push(reader.read_u2()?);
736            }
737            AttributeInfo::Exceptions {
738                exception_index_table,
739            }
740        }
741        "SourceFile" => AttributeInfo::SourceFile {
742            sourcefile_index: reader.read_u2()?,
743        },
744        "LineNumberTable" => {
745            let count = reader.read_u2()? as usize;
746            let mut entries = Vec::with_capacity(count);
747            for _ in 0..count {
748                entries.push(LineNumber {
749                    start_pc: reader.read_u2()?,
750                    line_number: reader.read_u2()?,
751                });
752            }
753            AttributeInfo::LineNumberTable { entries }
754        }
755        "LocalVariableTable" => {
756            let count = reader.read_u2()? as usize;
757            let mut entries = Vec::with_capacity(count);
758            for _ in 0..count {
759                entries.push(LocalVariable {
760                    start_pc: reader.read_u2()?,
761                    length: reader.read_u2()?,
762                    name_index: reader.read_u2()?,
763                    descriptor_index: reader.read_u2()?,
764                    index: reader.read_u2()?,
765                });
766            }
767            AttributeInfo::LocalVariableTable { entries }
768        }
769        "Signature" => AttributeInfo::Signature {
770            signature_index: reader.read_u2()?,
771        },
772        "StackMapTable" => {
773            let count = reader.read_u2()? as usize;
774            let mut entries = Vec::with_capacity(count);
775            for _ in 0..count {
776                let frame_type = reader.read_u1()?;
777                let frame = match frame_type {
778                    0..=63 => StackMapFrame::SameFrame {
779                        offset_delta: frame_type as u16,
780                    },
781                    64..=127 => StackMapFrame::SameLocals1StackItemFrame {
782                        offset_delta: (frame_type - 64) as u16,
783                        stack: parse_verification_type(&mut reader)?,
784                    },
785                    247 => StackMapFrame::SameLocals1StackItemFrameExtended {
786                        offset_delta: reader.read_u2()?,
787                        stack: parse_verification_type(&mut reader)?,
788                    },
789                    248..=250 => StackMapFrame::ChopFrame {
790                        offset_delta: reader.read_u2()?,
791                        k: 251 - frame_type,
792                    },
793                    251 => StackMapFrame::SameFrameExtended {
794                        offset_delta: reader.read_u2()?,
795                    },
796                    252..=254 => {
797                        let offset_delta = reader.read_u2()?;
798                        let locals_count = (frame_type - 251) as usize;
799                        let mut locals = Vec::with_capacity(locals_count);
800                        for _ in 0..locals_count {
801                            locals.push(parse_verification_type(&mut reader)?);
802                        }
803                        StackMapFrame::AppendFrame {
804                            offset_delta,
805                            locals,
806                        }
807                    }
808                    255 => {
809                        let offset_delta = reader.read_u2()?;
810                        let locals_count = reader.read_u2()? as usize;
811                        let mut locals = Vec::with_capacity(locals_count);
812                        for _ in 0..locals_count {
813                            locals.push(parse_verification_type(&mut reader)?);
814                        }
815                        let stack_count = reader.read_u2()? as usize;
816                        let mut stack = Vec::with_capacity(stack_count);
817                        for _ in 0..stack_count {
818                            stack.push(parse_verification_type(&mut reader)?);
819                        }
820                        StackMapFrame::FullFrame {
821                            offset_delta,
822                            locals,
823                            stack,
824                        }
825                    }
826                    _ => {
827                        return Err(ClassReadError::InvalidAttribute(
828                            "StackMapTable".to_string(),
829                        ));
830                    }
831                };
832                entries.push(frame);
833            }
834            AttributeInfo::StackMapTable { entries }
835        }
836        "Deprecated" => AttributeInfo::Deprecated,
837        "Synthetic" => AttributeInfo::Synthetic,
838        "InnerClasses" => {
839            let count = reader.read_u2()? as usize;
840            let mut classes = Vec::with_capacity(count);
841            for _ in 0..count {
842                classes.push(InnerClass {
843                    inner_class_info_index: reader.read_u2()?,
844                    outer_class_info_index: reader.read_u2()?,
845                    inner_name_index: reader.read_u2()?,
846                    inner_class_access_flags: reader.read_u2()?,
847                });
848            }
849            AttributeInfo::InnerClasses { classes }
850        }
851        "EnclosingMethod" => AttributeInfo::EnclosingMethod {
852            class_index: reader.read_u2()?,
853            method_index: reader.read_u2()?,
854        },
855        "BootstrapMethods" => {
856            let count = reader.read_u2()? as usize;
857            let mut methods = Vec::with_capacity(count);
858            for _ in 0..count {
859                let bootstrap_method_ref = reader.read_u2()?;
860                let arg_count = reader.read_u2()? as usize;
861                let mut bootstrap_arguments = Vec::with_capacity(arg_count);
862                for _ in 0..arg_count {
863                    bootstrap_arguments.push(reader.read_u2()?);
864                }
865                methods.push(BootstrapMethod {
866                    bootstrap_method_ref,
867                    bootstrap_arguments,
868                });
869            }
870            AttributeInfo::BootstrapMethods { methods }
871        }
872        "MethodParameters" => {
873            let count = reader.read_u1()? as usize;
874            let mut parameters = Vec::with_capacity(count);
875            for _ in 0..count {
876                parameters.push(MethodParameter {
877                    name_index: reader.read_u2()?,
878                    access_flags: reader.read_u2()?,
879                });
880            }
881            AttributeInfo::MethodParameters { parameters }
882        }
883        _ => {
884            return Ok(AttributeInfo::Unknown {
885                name: name.to_string(),
886                info,
887            });
888        }
889    };
890
891    if reader.remaining() != 0 {
892        return Err(ClassReadError::InvalidAttribute(name.to_string()));
893    }
894
895    Ok(attribute)
896}
897
898fn parse_verification_type(
899    reader: &mut ByteReader<'_>,
900) -> Result<VerificationTypeInfo, ClassReadError> {
901    let tag = reader.read_u1()?;
902    let kind = match tag {
903        0 => VerificationTypeInfo::Top,
904        1 => VerificationTypeInfo::Integer,
905        2 => VerificationTypeInfo::Float,
906        3 => VerificationTypeInfo::Double,
907        4 => VerificationTypeInfo::Long,
908        5 => VerificationTypeInfo::Null,
909        6 => VerificationTypeInfo::UninitializedThis,
910        7 => VerificationTypeInfo::Object {
911            cpool_index: reader.read_u2()?,
912        },
913        8 => VerificationTypeInfo::Uninitialized {
914            offset: reader.read_u2()?,
915        },
916        _ => {
917            return Err(ClassReadError::InvalidAttribute(
918                "StackMapTable".to_string(),
919            ));
920        }
921    };
922    Ok(kind)
923}
924
925fn cp_utf8(cp: &[CpInfo], index: u16) -> Result<&str, ClassReadError> {
926    match cp.get(index as usize) {
927        Some(CpInfo::Utf8(value)) => Ok(value.as_str()),
928        _ => Err(ClassReadError::InvalidIndex(index)),
929    }
930}
931
932fn cp_class_name(cp: &[CpInfo], index: u16) -> Result<&str, ClassReadError> {
933    match cp.get(index as usize) {
934        Some(CpInfo::Class { name_index }) => cp_utf8(cp, *name_index),
935        _ => Err(ClassReadError::InvalidIndex(index)),
936    }
937}
938
939fn cp_name_and_type(cp: &[CpInfo], index: u16) -> Result<(&str, &str), ClassReadError> {
940    match cp.get(index as usize) {
941        Some(CpInfo::NameAndType {
942            name_index,
943            descriptor_index,
944        }) => Ok((cp_utf8(cp, *name_index)?, cp_utf8(cp, *descriptor_index)?)),
945        _ => Err(ClassReadError::InvalidIndex(index)),
946    }
947}
948
949fn cp_field_ref(cp: &[CpInfo], index: u16) -> Result<(&str, &str, &str), ClassReadError> {
950    match cp.get(index as usize) {
951        Some(CpInfo::Fieldref {
952            class_index,
953            name_and_type_index,
954        }) => {
955            let owner = cp_class_name(cp, *class_index)?;
956            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
957            Ok((owner, name, desc))
958        }
959        _ => Err(ClassReadError::InvalidIndex(index)),
960    }
961}
962
963fn cp_method_ref(cp: &[CpInfo], index: u16) -> Result<(&str, &str, &str, bool), ClassReadError> {
964    match cp.get(index as usize) {
965        Some(CpInfo::Methodref {
966            class_index,
967            name_and_type_index,
968        }) => {
969            let owner = cp_class_name(cp, *class_index)?;
970            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
971            Ok((owner, name, desc, false))
972        }
973        Some(CpInfo::InterfaceMethodref {
974            class_index,
975            name_and_type_index,
976        }) => {
977            let owner = cp_class_name(cp, *class_index)?;
978            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
979            Ok((owner, name, desc, true))
980        }
981        _ => Err(ClassReadError::InvalidIndex(index)),
982    }
983}
984
985fn cp_invoke_dynamic(cp: &[CpInfo], index: u16) -> Result<(&str, &str), ClassReadError> {
986    match cp.get(index as usize) {
987        Some(CpInfo::InvokeDynamic {
988            name_and_type_index,
989            ..
990        }) => cp_name_and_type(cp, *name_and_type_index),
991        _ => Err(ClassReadError::InvalidIndex(index)),
992    }
993}
994
995fn cp_ldc_constant(cp: &[CpInfo], index: u16) -> Result<LdcConstant, ClassReadError> {
996    match cp.get(index as usize) {
997        Some(CpInfo::Integer(value)) => Ok(LdcConstant::Integer(*value)),
998        Some(CpInfo::Float(value)) => Ok(LdcConstant::Float(*value)),
999        Some(CpInfo::Long(value)) => Ok(LdcConstant::Long(*value)),
1000        Some(CpInfo::Double(value)) => Ok(LdcConstant::Double(*value)),
1001        Some(CpInfo::String { string_index }) => {
1002            Ok(LdcConstant::String(cp_utf8(cp, *string_index)?.to_string()))
1003        }
1004        Some(CpInfo::Class { name_index }) => {
1005            Ok(LdcConstant::Class(cp_utf8(cp, *name_index)?.to_string()))
1006        }
1007        Some(CpInfo::MethodType { descriptor_index }) => Ok(LdcConstant::MethodType(
1008            cp_utf8(cp, *descriptor_index)?.to_string(),
1009        )),
1010        Some(CpInfo::MethodHandle {
1011            reference_kind,
1012            reference_index,
1013        }) => Ok(LdcConstant::MethodHandle {
1014            reference_kind: *reference_kind,
1015            reference_index: *reference_index,
1016        }),
1017        Some(CpInfo::Dynamic { .. }) => Ok(LdcConstant::Dynamic),
1018        _ => Err(ClassReadError::InvalidIndex(index)),
1019    }
1020}
1021
1022fn decode_modified_utf8(bytes: &[u8]) -> Result<String, ClassReadError> {
1023    let mut code_units = Vec::with_capacity(bytes.len());
1024    let mut i = 0;
1025    while i < bytes.len() {
1026        let byte = bytes[i];
1027        if byte & 0x80 == 0 {
1028            code_units.push(byte as u16);
1029            i += 1;
1030        } else if byte & 0xE0 == 0xC0 {
1031            if i + 1 >= bytes.len() {
1032                return Err(ClassReadError::Utf8Error("truncated 2-byte".to_string()));
1033            }
1034            let byte2 = bytes[i + 1];
1035            if byte2 & 0xC0 != 0x80 {
1036                return Err(ClassReadError::Utf8Error("invalid 2-byte".to_string()));
1037            }
1038            let value = (((byte & 0x1F) as u16) << 6) | ((byte2 & 0x3F) as u16);
1039            code_units.push(value);
1040            i += 2;
1041        } else if byte & 0xF0 == 0xE0 {
1042            if i + 2 >= bytes.len() {
1043                return Err(ClassReadError::Utf8Error("truncated 3-byte".to_string()));
1044            }
1045            let byte2 = bytes[i + 1];
1046            let byte3 = bytes[i + 2];
1047            if byte2 & 0xC0 != 0x80 || byte3 & 0xC0 != 0x80 {
1048                return Err(ClassReadError::Utf8Error("invalid 3-byte".to_string()));
1049            }
1050            let value = (((byte & 0x0F) as u16) << 12)
1051                | (((byte2 & 0x3F) as u16) << 6)
1052                | ((byte3 & 0x3F) as u16);
1053            code_units.push(value);
1054            i += 3;
1055        } else {
1056            return Err(ClassReadError::Utf8Error(
1057                "invalid leading byte".to_string(),
1058            ));
1059        }
1060    }
1061
1062    String::from_utf16(&code_units)
1063        .map_err(|_| ClassReadError::Utf8Error("invalid utf16".to_string()))
1064}
1065
1066fn parse_code_instructions(code: &[u8]) -> Result<Vec<Insn>, ClassReadError> {
1067    let mut reader = CodeReader::new(code);
1068    let mut insns = Vec::new();
1069
1070    while reader.remaining() > 0 {
1071        let opcode_offset = reader.pos();
1072        let opcode = reader.read_u1()?;
1073        let insn = match opcode {
1074            0x00..=0x0F => Insn::Simple(InsnNode { opcode }),
1075            0x10 => Insn::Int(IntInsnNode {
1076                insn: InsnNode { opcode },
1077                operand: reader.read_i1()? as i32,
1078            }),
1079            0x11 => Insn::Int(IntInsnNode {
1080                insn: InsnNode { opcode },
1081                operand: reader.read_i2()? as i32,
1082            }),
1083            0x12 => Insn::Ldc(LdcInsnNode {
1084                insn: InsnNode { opcode },
1085                value: LdcValue::Index(reader.read_u1()? as u16),
1086            }),
1087            0x13 | 0x14 => Insn::Ldc(LdcInsnNode {
1088                insn: InsnNode { opcode },
1089                value: LdcValue::Index(reader.read_u2()?),
1090            }),
1091            0x15..=0x19 => Insn::Var(VarInsnNode {
1092                insn: InsnNode { opcode },
1093                var_index: reader.read_u1()? as u16,
1094            }),
1095            0x1A..=0x35 => Insn::Simple(InsnNode { opcode }),
1096            0x36..=0x3A => Insn::Var(VarInsnNode {
1097                insn: InsnNode { opcode },
1098                var_index: reader.read_u1()? as u16,
1099            }),
1100            0x3B..=0x56 => Insn::Simple(InsnNode { opcode }),
1101            0x57..=0x83 => Insn::Simple(InsnNode { opcode }),
1102            0x84 => Insn::Iinc(IincInsnNode {
1103                insn: InsnNode { opcode },
1104                var_index: reader.read_u1()? as u16,
1105                increment: reader.read_i1()? as i16,
1106            }),
1107            0x85..=0x98 => Insn::Simple(InsnNode { opcode }),
1108            0x99..=0xA8 => Insn::Jump(JumpInsnNode {
1109                insn: InsnNode { opcode },
1110                offset: reader.read_i2()? as i32,
1111            }),
1112            0xA9 => Insn::Var(VarInsnNode {
1113                insn: InsnNode { opcode },
1114                var_index: reader.read_u1()? as u16,
1115            }),
1116            0xAA => read_table_switch(&mut reader, opcode_offset)?,
1117            0xAB => read_lookup_switch(&mut reader, opcode_offset)?,
1118            0xAC..=0xB1 => Insn::Simple(InsnNode { opcode }),
1119            0xB2..=0xB5 => Insn::Field(FieldInsnNode {
1120                insn: InsnNode { opcode },
1121                field_ref: MemberRef::Index(reader.read_u2()?),
1122            }),
1123            0xB6..=0xB8 => Insn::Method(MethodInsnNode {
1124                insn: InsnNode { opcode },
1125                method_ref: MemberRef::Index(reader.read_u2()?),
1126            }),
1127            0xB9 => {
1128                let method_index = reader.read_u2()?;
1129                let count = reader.read_u1()?;
1130                let _ = reader.read_u1()?;
1131                Insn::InvokeInterface(InvokeInterfaceInsnNode {
1132                    insn: InsnNode { opcode },
1133                    method_index,
1134                    count,
1135                })
1136            }
1137            0xBA => {
1138                let method_index = reader.read_u2()?;
1139                let _ = reader.read_u2()?;
1140                Insn::InvokeDynamic(InvokeDynamicInsnNode {
1141                    insn: InsnNode { opcode },
1142                    method_index,
1143                })
1144            }
1145            0xBB => Insn::Type(TypeInsnNode {
1146                insn: InsnNode { opcode },
1147                type_index: reader.read_u2()?,
1148            }),
1149            0xBC => Insn::Int(IntInsnNode {
1150                insn: InsnNode { opcode },
1151                operand: reader.read_u1()? as i32,
1152            }),
1153            0xBD => Insn::Type(TypeInsnNode {
1154                insn: InsnNode { opcode },
1155                type_index: reader.read_u2()?,
1156            }),
1157            0xBE | 0xBF => Insn::Simple(InsnNode { opcode }),
1158            0xC0 | 0xC1 => Insn::Type(TypeInsnNode {
1159                insn: InsnNode { opcode },
1160                type_index: reader.read_u2()?,
1161            }),
1162            0xC2 | 0xC3 => Insn::Simple(InsnNode { opcode }),
1163            0xC4 => read_wide(&mut reader)?,
1164            0xC5 => Insn::MultiANewArray(MultiANewArrayInsnNode {
1165                insn: InsnNode { opcode },
1166                type_index: reader.read_u2()?,
1167                dimensions: reader.read_u1()?,
1168            }),
1169            0xC6 | 0xC7 => Insn::Jump(JumpInsnNode {
1170                insn: InsnNode { opcode },
1171                offset: reader.read_i2()? as i32,
1172            }),
1173            0xC8 | 0xC9 => Insn::Jump(JumpInsnNode {
1174                insn: InsnNode { opcode },
1175                offset: reader.read_i4()?,
1176            }),
1177            0xCA => Insn::Simple(InsnNode { opcode }),
1178            0xFE | 0xFF => Insn::Simple(InsnNode { opcode }),
1179            _ => {
1180                return Err(ClassReadError::InvalidOpcode {
1181                    opcode,
1182                    offset: opcode_offset,
1183                });
1184            }
1185        };
1186
1187        insns.push(insn);
1188    }
1189
1190    Ok(insns)
1191}
1192
1193pub(crate) fn parse_code_instructions_public(code: &[u8]) -> Result<Vec<Insn>, ClassReadError> {
1194    parse_code_instructions(code)
1195}
1196
1197#[derive(Debug, Clone)]
1198struct ParsedInstruction {
1199    offset: u16,
1200    insn: Insn,
1201}
1202
1203fn parse_code_instructions_with_offsets(
1204    code: &[u8],
1205) -> Result<Vec<ParsedInstruction>, ClassReadError> {
1206    let mut reader = CodeReader::new(code);
1207    let mut insns = Vec::new();
1208
1209    while reader.remaining() > 0 {
1210        let opcode_offset = reader.pos();
1211        let opcode = reader.read_u1()?;
1212        let insn = match opcode {
1213            0x00..=0x0F => Insn::Simple(InsnNode { opcode }),
1214            0x10 => Insn::Int(IntInsnNode {
1215                insn: InsnNode { opcode },
1216                operand: reader.read_i1()? as i32,
1217            }),
1218            0x11 => Insn::Int(IntInsnNode {
1219                insn: InsnNode { opcode },
1220                operand: reader.read_i2()? as i32,
1221            }),
1222            0x12 => Insn::Ldc(LdcInsnNode {
1223                insn: InsnNode { opcode },
1224                value: LdcValue::Index(reader.read_u1()? as u16),
1225            }),
1226            0x13 | 0x14 => Insn::Ldc(LdcInsnNode {
1227                insn: InsnNode { opcode },
1228                value: LdcValue::Index(reader.read_u2()?),
1229            }),
1230            0x15..=0x19 => Insn::Var(VarInsnNode {
1231                insn: InsnNode { opcode },
1232                var_index: reader.read_u1()? as u16,
1233            }),
1234            0x1A..=0x35 => Insn::Simple(InsnNode { opcode }),
1235            0x36..=0x3A => Insn::Var(VarInsnNode {
1236                insn: InsnNode { opcode },
1237                var_index: reader.read_u1()? as u16,
1238            }),
1239            0x3B..=0x56 => Insn::Simple(InsnNode { opcode }),
1240            0x57..=0x83 => Insn::Simple(InsnNode { opcode }),
1241            0x84 => Insn::Iinc(IincInsnNode {
1242                insn: InsnNode { opcode },
1243                var_index: reader.read_u1()? as u16,
1244                increment: reader.read_i1()? as i16,
1245            }),
1246            0x85..=0x98 => Insn::Simple(InsnNode { opcode }),
1247            0x99..=0xA8 => Insn::Jump(JumpInsnNode {
1248                insn: InsnNode { opcode },
1249                offset: reader.read_i2()? as i32,
1250            }),
1251            0xA9 => Insn::Var(VarInsnNode {
1252                insn: InsnNode { opcode },
1253                var_index: reader.read_u1()? as u16,
1254            }),
1255            0xAA => read_table_switch(&mut reader, opcode_offset)?,
1256            0xAB => read_lookup_switch(&mut reader, opcode_offset)?,
1257            0xAC..=0xB1 => Insn::Simple(InsnNode { opcode }),
1258            0xB2..=0xB5 => Insn::Field(FieldInsnNode {
1259                insn: InsnNode { opcode },
1260                field_ref: MemberRef::Index(reader.read_u2()?),
1261            }),
1262            0xB6..=0xB8 => Insn::Method(MethodInsnNode {
1263                insn: InsnNode { opcode },
1264                method_ref: MemberRef::Index(reader.read_u2()?),
1265            }),
1266            0xB9 => {
1267                let method_index = reader.read_u2()?;
1268                let count = reader.read_u1()?;
1269                let _ = reader.read_u1()?;
1270                Insn::InvokeInterface(InvokeInterfaceInsnNode {
1271                    insn: InsnNode { opcode },
1272                    method_index,
1273                    count,
1274                })
1275            }
1276            0xBA => {
1277                let method_index = reader.read_u2()?;
1278                let _ = reader.read_u2()?;
1279                Insn::InvokeDynamic(InvokeDynamicInsnNode {
1280                    insn: InsnNode { opcode },
1281                    method_index,
1282                })
1283            }
1284            0xBB => Insn::Type(TypeInsnNode {
1285                insn: InsnNode { opcode },
1286                type_index: reader.read_u2()?,
1287            }),
1288            0xBC => Insn::Int(IntInsnNode {
1289                insn: InsnNode { opcode },
1290                operand: reader.read_u1()? as i32,
1291            }),
1292            0xBD => Insn::Type(TypeInsnNode {
1293                insn: InsnNode { opcode },
1294                type_index: reader.read_u2()?,
1295            }),
1296            0xBE | 0xBF => Insn::Simple(InsnNode { opcode }),
1297            0xC0 | 0xC1 => Insn::Type(TypeInsnNode {
1298                insn: InsnNode { opcode },
1299                type_index: reader.read_u2()?,
1300            }),
1301            0xC2 | 0xC3 => Insn::Simple(InsnNode { opcode }),
1302            0xC4 => read_wide(&mut reader)?,
1303            0xC5 => Insn::MultiANewArray(MultiANewArrayInsnNode {
1304                insn: InsnNode { opcode },
1305                type_index: reader.read_u2()?,
1306                dimensions: reader.read_u1()?,
1307            }),
1308            0xC6 | 0xC7 => Insn::Jump(JumpInsnNode {
1309                insn: InsnNode { opcode },
1310                offset: reader.read_i2()? as i32,
1311            }),
1312            0xC8 | 0xC9 => Insn::Jump(JumpInsnNode {
1313                insn: InsnNode { opcode },
1314                offset: reader.read_i4()?,
1315            }),
1316            0xCA => Insn::Simple(InsnNode { opcode }),
1317            0xFE | 0xFF => Insn::Simple(InsnNode { opcode }),
1318            _ => {
1319                return Err(ClassReadError::InvalidOpcode {
1320                    opcode,
1321                    offset: opcode_offset,
1322                });
1323            }
1324        };
1325
1326        insns.push(ParsedInstruction {
1327            offset: opcode_offset as u16,
1328            insn,
1329        });
1330    }
1331
1332    Ok(insns)
1333}
1334
1335fn build_insn_nodes(
1336    code: &[u8],
1337    exception_table: &[ExceptionTableEntry],
1338    cp: &[CpInfo],
1339) -> Result<(Vec<AbstractInsnNode>, Vec<TryCatchBlockNode>), ClassReadError> {
1340    let instructions = parse_code_instructions_with_offsets(code)?;
1341    let mut offsets = std::collections::HashSet::new();
1342    for instruction in &instructions {
1343        offsets.insert(instruction.offset);
1344        match &instruction.insn {
1345            Insn::Jump(node) => {
1346                offsets.insert((instruction.offset as i32 + node.offset) as u16);
1347            }
1348            Insn::TableSwitch(node) => {
1349                offsets.insert((instruction.offset as i32 + node.default_offset) as u16);
1350                for offset in &node.offsets {
1351                    offsets.insert((instruction.offset as i32 + *offset) as u16);
1352                }
1353            }
1354            Insn::LookupSwitch(node) => {
1355                offsets.insert((instruction.offset as i32 + node.default_offset) as u16);
1356                for (_, offset) in &node.pairs {
1357                    offsets.insert((instruction.offset as i32 + *offset) as u16);
1358                }
1359            }
1360            _ => {}
1361        }
1362    }
1363    for entry in exception_table {
1364        offsets.insert(entry.start_pc);
1365        offsets.insert(entry.end_pc);
1366        offsets.insert(entry.handler_pc);
1367    }
1368    offsets.insert(code.len() as u16);
1369
1370    let mut label_by_offset = std::collections::HashMap::new();
1371    for (next_id, offset) in offsets.into_iter().enumerate() {
1372        label_by_offset.insert(offset, LabelNode { id: next_id });
1373    }
1374
1375    let mut nodes = Vec::new();
1376    for instruction in instructions {
1377        if let Some(label) = label_by_offset.get(&{ instruction.offset }) {
1378            nodes.push(AbstractInsnNode::Label(*label));
1379        }
1380        nodes.push(AbstractInsnNode::Insn(instruction.insn));
1381    }
1382    if let Some(label) = label_by_offset.get(&(code.len() as u16)) {
1383        nodes.push(AbstractInsnNode::Label(*label));
1384    }
1385
1386    let mut try_catch_blocks = Vec::new();
1387    for entry in exception_table {
1388        let start = *label_by_offset
1389            .get(&entry.start_pc)
1390            .ok_or_else(|| ClassReadError::InvalidAttribute("missing start label".to_string()))?;
1391        let end = *label_by_offset
1392            .get(&entry.end_pc)
1393            .ok_or_else(|| ClassReadError::InvalidAttribute("missing end label".to_string()))?;
1394        let handler = *label_by_offset
1395            .get(&entry.handler_pc)
1396            .ok_or_else(|| ClassReadError::InvalidAttribute("missing handler label".to_string()))?;
1397        let catch_type = if entry.catch_type == 0 {
1398            None
1399        } else {
1400            Some(cp_class_name(cp, entry.catch_type)?.to_string())
1401        };
1402        try_catch_blocks.push(TryCatchBlockNode {
1403            start,
1404            end,
1405            handler,
1406            catch_type,
1407        });
1408    }
1409
1410    Ok((nodes, try_catch_blocks))
1411}
1412
1413pub(crate) fn build_insn_nodes_public(
1414    code: &[u8],
1415    exception_table: &[ExceptionTableEntry],
1416    cp: &[CpInfo],
1417) -> Result<(Vec<AbstractInsnNode>, Vec<TryCatchBlockNode>), ClassReadError> {
1418    build_insn_nodes(code, exception_table, cp)
1419}
1420
1421fn read_table_switch(
1422    reader: &mut CodeReader<'_>,
1423    opcode_offset: usize,
1424) -> Result<Insn, ClassReadError> {
1425    reader.align4(opcode_offset)?;
1426    let default_offset = reader.read_i4()?;
1427    let low = reader.read_i4()?;
1428    let high = reader.read_i4()?;
1429    let count = if high < low {
1430        0
1431    } else {
1432        (high - low + 1) as usize
1433    };
1434    let mut offsets = Vec::with_capacity(count);
1435    for _ in 0..count {
1436        offsets.push(reader.read_i4()?);
1437    }
1438    Ok(Insn::TableSwitch(TableSwitchInsnNode {
1439        insn: InsnNode { opcode: 0xAA },
1440        default_offset,
1441        low,
1442        high,
1443        offsets,
1444    }))
1445}
1446
1447fn read_lookup_switch(
1448    reader: &mut CodeReader<'_>,
1449    opcode_offset: usize,
1450) -> Result<Insn, ClassReadError> {
1451    reader.align4(opcode_offset)?;
1452    let default_offset = reader.read_i4()?;
1453    let npairs = reader.read_i4()? as usize;
1454    let mut pairs = Vec::with_capacity(npairs);
1455    for _ in 0..npairs {
1456        let key = reader.read_i4()?;
1457        let offset = reader.read_i4()?;
1458        pairs.push((key, offset));
1459    }
1460    Ok(Insn::LookupSwitch(LookupSwitchInsnNode {
1461        insn: InsnNode { opcode: 0xAB },
1462        default_offset,
1463        pairs,
1464    }))
1465}
1466
1467fn read_wide(reader: &mut CodeReader<'_>) -> Result<Insn, ClassReadError> {
1468    let opcode = reader.read_u1()?;
1469    match opcode {
1470        0x15..=0x19 | 0x36..=0x3A | 0xA9 => Ok(Insn::Var(VarInsnNode {
1471            insn: InsnNode { opcode },
1472            var_index: reader.read_u2()?,
1473        })),
1474        0x84 => Ok(Insn::Iinc(IincInsnNode {
1475            insn: InsnNode { opcode },
1476            var_index: reader.read_u2()?,
1477            increment: reader.read_i2()?,
1478        })),
1479        _ => Err(ClassReadError::InvalidOpcode {
1480            opcode,
1481            offset: reader.pos().saturating_sub(1),
1482        }),
1483    }
1484}
1485
1486fn visit_instruction(
1487    cp: &[CpInfo],
1488    offset: i32,
1489    insn: Insn,
1490    mv: &mut dyn MethodVisitor,
1491) -> Result<(), ClassReadError> {
1492    match insn {
1493        Insn::Simple(node) => {
1494            mv.visit_insn(node.opcode);
1495        }
1496        Insn::Int(node) => {
1497            mv.visit_int_insn(node.insn.opcode, node.operand);
1498        }
1499        Insn::Var(node) => {
1500            mv.visit_var_insn(node.insn.opcode, node.var_index);
1501        }
1502        Insn::Type(node) => {
1503            let type_name = cp_class_name(cp, node.type_index)?;
1504            mv.visit_type_insn(node.insn.opcode, type_name);
1505        }
1506        Insn::Field(node) => {
1507            let index = match node.field_ref {
1508                MemberRef::Index(index) => index,
1509                MemberRef::Symbolic { .. } => {
1510                    return Err(ClassReadError::InvalidIndex(0));
1511                }
1512            };
1513            let (owner, name, desc) = cp_field_ref(cp, index)?;
1514            mv.visit_field_insn(node.insn.opcode, owner, name, desc);
1515        }
1516        Insn::Method(node) => {
1517            let index = match node.method_ref {
1518                MemberRef::Index(index) => index,
1519                MemberRef::Symbolic { .. } => {
1520                    return Err(ClassReadError::InvalidIndex(0));
1521                }
1522            };
1523            let (owner, name, desc, is_interface) = cp_method_ref(cp, index)?;
1524            mv.visit_method_insn(node.insn.opcode, owner, name, desc, is_interface);
1525        }
1526        Insn::InvokeInterface(node) => {
1527            let (owner, name, desc, _is_interface) = cp_method_ref(cp, node.method_index)?;
1528            mv.visit_method_insn(node.insn.opcode, owner, name, desc, true);
1529        }
1530        Insn::InvokeDynamic(node) => {
1531            let (name, desc) = cp_invoke_dynamic(cp, node.method_index)?;
1532            mv.visit_invoke_dynamic_insn(name, desc);
1533        }
1534        Insn::Jump(node) => {
1535            let target = offset + node.offset;
1536            mv.visit_jump_insn(node.insn.opcode, target);
1537        }
1538        Insn::Ldc(node) => {
1539            let index = match node.value {
1540                LdcValue::Index(index) => index,
1541                LdcValue::String(value) => {
1542                    mv.visit_ldc_insn(LdcConstant::String(value));
1543                    return Ok(());
1544                }
1545            };
1546            let constant = cp_ldc_constant(cp, index)?;
1547            mv.visit_ldc_insn(constant);
1548        }
1549        Insn::Iinc(node) => {
1550            mv.visit_iinc_insn(node.var_index, node.increment);
1551        }
1552        Insn::TableSwitch(node) => {
1553            let targets = node
1554                .offsets
1555                .iter()
1556                .map(|value| offset + *value)
1557                .collect::<Vec<_>>();
1558            mv.visit_table_switch(offset + node.default_offset, node.low, node.high, &targets);
1559        }
1560        Insn::LookupSwitch(node) => {
1561            let pairs = node
1562                .pairs
1563                .iter()
1564                .map(|(key, value)| (*key, offset + *value))
1565                .collect::<Vec<_>>();
1566            mv.visit_lookup_switch(offset + node.default_offset, &pairs);
1567        }
1568        Insn::MultiANewArray(node) => {
1569            let type_name = cp_class_name(cp, node.type_index)?;
1570            mv.visit_multi_anewarray_insn(type_name, node.dimensions);
1571        }
1572    }
1573    Ok(())
1574}
1575
1576struct CodeReader<'a> {
1577    data: &'a [u8],
1578    pos: usize,
1579}
1580
1581impl<'a> CodeReader<'a> {
1582    fn new(data: &'a [u8]) -> Self {
1583        Self { data, pos: 0 }
1584    }
1585
1586    fn remaining(&self) -> usize {
1587        self.data.len().saturating_sub(self.pos)
1588    }
1589
1590    fn pos(&self) -> usize {
1591        self.pos
1592    }
1593
1594    fn align4(&mut self, opcode_offset: usize) -> Result<(), ClassReadError> {
1595        let mut padding = (4 - ((opcode_offset + 1) % 4)) % 4;
1596        while padding > 0 {
1597            self.read_u1()?;
1598            padding -= 1;
1599        }
1600        Ok(())
1601    }
1602
1603    fn read_u1(&mut self) -> Result<u8, ClassReadError> {
1604        if self.pos >= self.data.len() {
1605            return Err(ClassReadError::UnexpectedEof);
1606        }
1607        let value = self.data[self.pos];
1608        self.pos += 1;
1609        Ok(value)
1610    }
1611
1612    fn read_i1(&mut self) -> Result<i8, ClassReadError> {
1613        Ok(self.read_u1()? as i8)
1614    }
1615
1616    fn read_u2(&mut self) -> Result<u16, ClassReadError> {
1617        let bytes = self.read_bytes(2)?;
1618        Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
1619    }
1620
1621    fn read_i2(&mut self) -> Result<i16, ClassReadError> {
1622        Ok(self.read_u2()? as i16)
1623    }
1624
1625    fn read_i4(&mut self) -> Result<i32, ClassReadError> {
1626        let bytes = self.read_bytes(4)?;
1627        Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
1628    }
1629
1630    fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, ClassReadError> {
1631        if self.pos + len > self.data.len() {
1632            return Err(ClassReadError::UnexpectedEof);
1633        }
1634        let bytes = self.data[self.pos..self.pos + len].to_vec();
1635        self.pos += len;
1636        Ok(bytes)
1637    }
1638}
1639
1640struct ByteReader<'a> {
1641    data: &'a [u8],
1642    pos: usize,
1643}
1644
1645impl<'a> ByteReader<'a> {
1646    fn new(data: &'a [u8]) -> Self {
1647        Self { data, pos: 0 }
1648    }
1649
1650    fn remaining(&self) -> usize {
1651        self.data.len().saturating_sub(self.pos)
1652    }
1653
1654    fn read_u1(&mut self) -> Result<u8, ClassReadError> {
1655        if self.pos >= self.data.len() {
1656            return Err(ClassReadError::UnexpectedEof);
1657        }
1658        let value = self.data[self.pos];
1659        self.pos += 1;
1660        Ok(value)
1661    }
1662
1663    fn read_u2(&mut self) -> Result<u16, ClassReadError> {
1664        let bytes = self.read_bytes(2)?;
1665        Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
1666    }
1667
1668    fn read_u4(&mut self) -> Result<u32, ClassReadError> {
1669        let bytes = self.read_bytes(4)?;
1670        Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
1671    }
1672
1673    fn read_u8(&mut self) -> Result<u64, ClassReadError> {
1674        let bytes = self.read_bytes(8)?;
1675        Ok(u64::from_be_bytes([
1676            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
1677        ]))
1678    }
1679
1680    fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, ClassReadError> {
1681        if self.pos + len > self.data.len() {
1682            return Err(ClassReadError::UnexpectedEof);
1683        }
1684        let bytes = self.data[self.pos..self.pos + len].to_vec();
1685        self.pos += len;
1686        Ok(bytes)
1687    }
1688}