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