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