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(
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 code = method.attributes.iter().find_map(|attr| match attr {
409 AttributeInfo::Code(code) => Some(code.clone()),
410 _ => None,
411 });
412 methods.push(crate::nodes::MethodNode {
413 access_flags: method.access_flags,
414 name_index: method.name_index,
415 descriptor_index: method.descriptor_index,
416 name,
417 descriptor,
418 code,
419 attributes: method.attributes.clone(),
420 });
421 }
422
423 Ok(crate::nodes::ClassNode {
424 minor_version: self.minor_version,
425 major_version: self.major_version,
426 access_flags: self.access_flags,
427 constant_pool: self.constant_pool.clone(),
428 this_class: self.this_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 LdcValue::Int(value) => {
1623 mv.visit_ldc_insn(LdcConstant::Integer(value));
1624 return Ok(());
1625 }
1626 LdcValue::Float(value) => {
1627 mv.visit_ldc_insn(LdcConstant::Float(value));
1628 return Ok(());
1629 }
1630 LdcValue::Long(value) => {
1631 mv.visit_ldc_insn(LdcConstant::Long(value));
1632 return Ok(());
1633 }
1634 LdcValue::Double(value) => {
1635 mv.visit_ldc_insn(LdcConstant::Double(value));
1636 return Ok(());
1637 }
1638 };
1639 let constant = cp_ldc_constant(cp, index)?;
1640 mv.visit_ldc_insn(constant);
1641 }
1642 Insn::Iinc(node) => {
1643 mv.visit_iinc_insn(node.var_index, node.increment);
1644 }
1645 Insn::TableSwitch(node) => {
1646 let targets = node
1647 .offsets
1648 .iter()
1649 .map(|value| offset + *value)
1650 .collect::<Vec<_>>();
1651 mv.visit_table_switch(offset + node.default_offset, node.low, node.high, &targets);
1652 }
1653 Insn::LookupSwitch(node) => {
1654 let pairs = node
1655 .pairs
1656 .iter()
1657 .map(|(key, value)| (*key, offset + *value))
1658 .collect::<Vec<_>>();
1659 mv.visit_lookup_switch(offset + node.default_offset, &pairs);
1660 }
1661 Insn::MultiANewArray(node) => {
1662 let type_name = cp_class_name(cp, node.type_index)?;
1663 mv.visit_multi_anewarray_insn(type_name, node.dimensions);
1664 }
1665 }
1666 Ok(())
1667}
1668
1669pub struct ByteReader<'a> {
1670 data: &'a [u8],
1671 pos: usize,
1672}
1673
1674impl<'a> ByteReader<'a> {
1675 pub fn new(data: &'a [u8]) -> Self {
1676 Self { data, pos: 0 }
1677 }
1678
1679 pub fn remaining(&self) -> usize {
1680 self.data.len().saturating_sub(self.pos)
1681 }
1682
1683 pub fn pos(&self) -> usize {
1684 self.pos
1685 }
1686
1687 pub fn align4(&mut self, opcode_offset: usize) -> Result<(), ClassReadError> {
1688 let mut padding = (4 - ((opcode_offset + 1) % 4)) % 4;
1689 while padding > 0 {
1690 self.read_u1()?;
1691 padding -= 1;
1692 }
1693 Ok(())
1694 }
1695
1696 pub fn read_u1(&mut self) -> Result<u8, ClassReadError> {
1697 if self.pos >= self.data.len() {
1698 return Err(ClassReadError::UnexpectedEof);
1699 }
1700 let value = self.data[self.pos];
1701 self.pos += 1;
1702 Ok(value)
1703 }
1704
1705 pub fn read_i1(&mut self) -> Result<i8, ClassReadError> {
1706 Ok(self.read_u1()? as i8)
1707 }
1708
1709 pub fn read_u2(&mut self) -> Result<u16, ClassReadError> {
1710 let bytes = self.read_bytes(2)?;
1711 Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
1712 }
1713
1714 pub fn read_i2(&mut self) -> Result<i16, ClassReadError> {
1715 Ok(self.read_u2()? as i16)
1716 }
1717
1718 pub fn read_u4(&mut self) -> Result<u32, ClassReadError> {
1719 let bytes = self.read_bytes(4)?;
1720 Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
1721 }
1722
1723 pub fn read_i4(&mut self) -> Result<i32, ClassReadError> {
1724 let bytes = self.read_bytes(4)?;
1725 Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
1726 }
1727
1728 pub fn read_u8(&mut self) -> Result<u64, ClassReadError> {
1729 let bytes = self.read_bytes(8)?;
1730 Ok(u64::from_be_bytes([
1731 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
1732 ]))
1733 }
1734
1735 pub fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, ClassReadError> {
1736 if self.pos + len > self.data.len() {
1737 return Err(ClassReadError::UnexpectedEof);
1738 }
1739 let bytes = self.data[self.pos..self.pos + len].to_vec();
1740 self.pos += len;
1741 Ok(bytes)
1742 }
1743}
1744
1745#[cfg(test)]
1746mod tests {
1747 use super::*;
1748 use std::cell::RefCell;
1749 use std::rc::Rc;
1750
1751 struct MockClassVisitor {
1753 pub visited_name: Rc<RefCell<Option<String>>>,
1754 pub visited_methods: Rc<RefCell<Vec<String>>>,
1755 }
1756
1757 impl MockClassVisitor {
1758 fn new() -> Self {
1759 Self {
1760 visited_name: Rc::new(RefCell::new(None)),
1761 visited_methods: Rc::new(RefCell::new(Vec::new())),
1762 }
1763 }
1764 }
1765
1766 impl ClassVisitor for MockClassVisitor {
1767 fn visit(
1768 &mut self,
1769 _major: u16,
1770 _minor: u16,
1771 _access_flags: u16,
1772 name: &str,
1773 _super_name: Option<&str>,
1774 _interfaces: &[String],
1775 ) {
1776 *self.visited_name.borrow_mut() = Some(name.to_string());
1777 }
1778
1779 fn visit_method(
1780 &mut self,
1781 _access_flags: u16,
1782 name: &str,
1783 _descriptor: &str,
1784 ) -> Option<Box<dyn MethodVisitor>> {
1785 self.visited_methods.borrow_mut().push(name.to_string());
1786 None
1787 }
1788 }
1789
1790 fn generate_minimal_class() -> Vec<u8> {
1793 let mut w = Vec::new();
1794 w.extend_from_slice(&0xCAFEBABE_u32.to_be_bytes());
1796 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);
1809 let name = "TestClass";
1810 w.extend_from_slice(&(name.len() as u16).to_be_bytes());
1811 w.extend_from_slice(name.as_bytes());
1812
1813 w.push(7);
1815 w.extend_from_slice(&1_u16.to_be_bytes());
1816
1817 w.push(1);
1819 let obj = "java/lang/Object";
1820 w.extend_from_slice(&(obj.len() as u16).to_be_bytes());
1821 w.extend_from_slice(obj.as_bytes());
1822
1823 w.push(7);
1825 w.extend_from_slice(&3_u16.to_be_bytes());
1826
1827 w.extend_from_slice(&0x0021_u16.to_be_bytes());
1829 w.extend_from_slice(&2_u16.to_be_bytes());
1831 w.extend_from_slice(&4_u16.to_be_bytes());
1833
1834 w.extend_from_slice(&0_u16.to_be_bytes());
1836 w.extend_from_slice(&0_u16.to_be_bytes());
1838 w.extend_from_slice(&0_u16.to_be_bytes());
1840 w.extend_from_slice(&0_u16.to_be_bytes());
1842
1843 w
1844 }
1845
1846 #[test]
1847 fn test_class_reader_header() {
1848 let bytes = generate_minimal_class();
1849 let reader = ClassReader::new(&bytes);
1850 let mut visitor = MockClassVisitor::new();
1851
1852 let result = reader.accept(&mut visitor, 0);
1853
1854 assert!(result.is_ok(), "Should parse valid class file");
1855 assert_eq!(
1856 *visitor.visited_name.borrow(),
1857 Some("TestClass".to_string())
1858 );
1859 }
1860
1861 #[test]
1862 fn test_invalid_magic() {
1863 let bytes = vec![0x00, 0x00, 0x00, 0x00];
1865 let reader = ClassReader::new(&bytes);
1866 let mut visitor = MockClassVisitor::new();
1867
1868 let result = reader.accept(&mut visitor, 0);
1869 assert!(matches!(result, Err(ClassReadError::InvalidMagic(_))));
1870 }
1871
1872 #[test]
1873 fn test_code_reader_alignment() {
1874 let data = vec![0x00, 0x00, 0x00, 0x00]; let mut reader = super::ByteReader::new(&data);
1877
1878 reader.pos = 1;
1880 assert!(reader.align4(0).is_ok());
1882 assert_eq!(reader.pos(), 4);
1883 }
1884}