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