1use super::{
2 AssemblyRefIndex, EntryPoint, ExportedTypeIndex, FieldIndex, FileIndex, MethodIndex, MethodMemberIndex,
3 MethodRefIndex, ModuleRefIndex, PropertyIndex, Resolution, TypeIndex, TypeRefIndex, lazy,
4};
5use crate::binary::{heap::*, metadata};
6use crate::convert::{self, TypeKind};
7use crate::dll::{DLL, DLLError, ParseError, ResolveError, Result, ValidityError};
8use crate::prelude::generic::{Constraint, Generic, SpecialConstraint, Variance};
9use crate::resolved::{types::MemberType, *};
10use rustc_hash::FxHashMap as HashMap;
11use scroll::Pread;
12use std::{borrow::Cow, sync::Arc};
13use tracing::{debug, warn};
14
15#[derive(Debug, Default, Copy, Clone)]
17pub struct Options {
18 pub skip_method_bodies: bool,
23
24 pub lazy_method_bodies: bool,
37
38 pub lazy_method_signatures: bool,
54
55 pub lazy_property_signatures: bool,
69
70 pub lazy_attributes: bool,
100}
101
102macro_rules! heap_idx {
103 ($heap:ident, $idx:expr) => {
104 Cow::Borrowed($heap.at_index($idx)?)
105 };
106}
107
108macro_rules! optional_idx {
109 ($heap:ident, $idx:expr) => {
110 if $idx.is_null() {
111 None
112 } else {
113 Some(heap_idx!($heap, $idx))
114 }
115 };
116}
117
118macro_rules! build_version {
119 ($src:ident) => {
120 Version {
121 major: $src.major_version,
122 minor: $src.minor_version,
123 build: $src.build_number,
124 revision: $src.revision_number,
125 }
126 };
127}
128
129macro_rules! build_vec {
133 ($name:ident = $t:ty[$len:expr], $body:expr) => {
134 let mut $name = vec![std::mem::MaybeUninit::uninit(); $len];
135 $body;
136 let mut $name = std::mem::ManuallyDrop::new($name);
138 #[allow(unused_mut)]
141 let mut $name = unsafe { Vec::from_raw_parts($name.as_mut_ptr().cast::<$t>(), $name.len(), $name.capacity()) };
142 };
143}
144
145macro_rules! stage_start {
146 ($start:ident) => {
147 #[cfg(feature = "stage-timing")]
148 let $start = std::time::Instant::now();
149 };
150}
151
152macro_rules! stage_end {
153 ($start:ident, $name:literal) => {
154 #[cfg(feature = "stage-timing")]
155 {
156 let elapsed = $start.elapsed();
157 debug!(
158 stage = $name,
159 elapsed_ns = elapsed.as_nanos() as u64,
160 elapsed = ?elapsed,
161 "read_impl stage timing"
162 );
163 }
164 };
165}
166
167const MIN_PAR_LEN: usize = 256;
171
172#[inline]
173fn resolve_oob(kind: &'static str, index: usize, max: usize) -> DLLError {
174 ResolveError::IndexOutOfRange { kind, index, max }.into()
175}
176
177#[inline]
178fn resolve_bad_target(context: &'static str) -> DLLError {
179 ResolveError::BadTokenTarget { context }.into()
180}
181
182#[inline]
183fn resolve_missing_row(table: &'static str, index: usize) -> DLLError {
184 ResolveError::MissingRow { table, index }.into()
185}
186
187#[inline]
188fn resolve_index_arithmetic(context: &'static str) -> DLLError {
189 ResolveError::IndexArithmetic { context }.into()
190}
191
192#[inline]
193fn validity_bad_flags(context: &'static str, flags: u32) -> DLLError {
194 ValidityError::BadFlags { context, flags }.into()
195}
196
197fn extract_method<'a>(
203 parent: &mut types::TypeDefinition<'a>,
204 idx: MethodIndex,
205 methods: &mut [MethodIndex],
206 tables: &metadata::table::Tables,
207) -> std::result::Result<members::Method<'a>, DLLError> {
208 let MethodMemberIndex::Method(internal_idx) = idx.member else {
209 debug_assert!(false, "unreachable extract_method called with non-method member index");
211 unreachable!()
212 };
213
214 if let Ok(start_idx) = methods.binary_search_by_key(&idx.parent_type, |m| m.parent_type) {
215 let mut max_internal: Option<(usize, usize)> = None;
217
218 let mut find_max = |start: usize, inc: isize, stop: usize| -> Result<()> {
220 let mut current_index = start;
221 while methods[current_index].parent_type == idx.parent_type {
222 if let MethodMemberIndex::Method(i) = methods[current_index].member {
223 match &max_internal {
224 Some((_, max_i)) if i <= *max_i => {}
225 _ => {
226 max_internal = Some((current_index, i));
227 }
228 }
229 }
230 if current_index == stop {
231 break;
232 }
233 current_index = current_index.checked_add_signed(inc).ok_or(ResolveError::IndexArithmetic {
234 context: "extract_method walk",
235 })?;
236 }
237 Ok(())
238 };
239
240 find_max(start_idx, 1, tables.method_def.len() - 1)?;
243 if start_idx != 0 {
244 find_max(start_idx - 1, -1, 0)?;
245 }
246
247 if let Some((max_index, _)) = max_internal {
250 methods[max_index].member = MethodMemberIndex::Method(internal_idx);
251 }
252 }
253
254 Ok(parent.methods.swap_remove(internal_idx))
255}
256
257fn make_generic<'a, T: TypeKind>(
258 name: Cow<'a, str>,
259 p: &metadata::table::GenericParam,
260 param_idx: usize,
261 constraint_map: &mut HashMap<usize, (usize, usize)>,
262 tables: &metadata::table::Tables,
263 ctx: &convert::read::Context<'_, 'a>,
264) -> Result<Generic<'a, T>> {
265 Ok(Generic {
266 attributes: vec![],
267 variance: match p.flags & 0x3 {
268 0x0 => Variance::Invariant,
269 0x1 => Variance::Covariant,
270 0x2 => Variance::Contravariant,
271 _ => dll_bail!(ValidityError::BadVarianceFlags { flags: p.flags }),
272 },
273 name,
274 special_constraint: SpecialConstraint {
275 reference_type: check_bitmask!(p.flags, 0x04),
276 value_type: check_bitmask!(p.flags, 0x08),
277 has_default_constructor: check_bitmask!(p.flags, 0x10),
278 },
279 type_constraints: {
280 let constraints = &tables.generic_param_constraint;
281 let owner = param_idx + 1;
282 let start = constraints.partition_point(|c| c.owner.0 < owner);
283
284 let mut type_constraints = Vec::new();
285 let mut c_idx = start;
286
287 while let Some(c) = constraints.get(c_idx) {
288 if c.owner.0 != owner {
289 break;
290 }
291
292 let (cmod, ty) = convert::read::idx_with_mod(c.constraint, ctx)?;
293 let internal = type_constraints.len();
294 constraint_map.insert(c_idx, (param_idx, internal));
295 type_constraints.push(Constraint {
296 attributes: vec![],
297 custom_modifiers: cmod,
298 constraint_type: ty,
299 });
300
301 c_idx += 1;
302 }
303
304 type_constraints
305 },
306 })
307}
308
309fn member_accessibility(flags: u16) -> Result<members::Accessibility> {
310 use Accessibility::*;
311 use members::Accessibility::*;
312
313 Ok(match flags & 0x7 {
314 0x0 => CompilerControlled,
315 0x1 => Access(Private),
316 0x2 => Access(FamilyANDAssembly),
317 0x3 => Access(Assembly),
318 0x4 => Access(Family),
319 0x5 => Access(FamilyORAssembly),
320 0x6 => Access(Public),
321 bad => dll_bail!(validity_bad_flags("member accessibility", u32::from(bad))),
322 })
323}
324
325fn decode_assembly<'a>(
326 tables: &metadata::table::Tables,
327 strings: &StringsReader<'a>,
328 blobs: &BlobReader<'a>,
329) -> Result<Option<assembly::Assembly<'a>>> {
330 let mut assembly = None;
331 if let Some(a) = tables.assembly.first() {
332 use assembly::*;
333
334 assembly = Some(Assembly {
335 attributes: vec![],
336 hash_algorithm: match a.hash_alg_id {
337 0x0000 => HashAlgorithm::None,
338 0x8003 => HashAlgorithm::ReservedMD5,
339 0x8004 => HashAlgorithm::SHA1,
340 _other => dll_bail!(ParseError::BadStructure("unrecognized assembly hash algorithm")),
341 },
342 version: build_version!(a),
343 flags: Flags::new(a.flags),
344 public_key: optional_idx!(blobs, a.public_key),
345 name: heap_idx!(strings, a.name),
346 culture: optional_idx!(strings, a.culture),
347 security: None,
348 });
349 }
350
351 Ok(assembly)
352}
353
354fn decode_assembly_refs<'a>(
355 tables: &metadata::table::Tables,
356 strings: &StringsReader<'a>,
357 blobs: &BlobReader<'a>,
358) -> Result<Vec<assembly::ExternalAssemblyReference<'a>>> {
359 use rayon::prelude::*;
360
361 let refs = tables
362 .assembly_ref
363 .par_iter()
364 .with_min_len(MIN_PAR_LEN)
365 .map(|a| {
366 use assembly::*;
367 Ok(ExternalAssemblyReference {
368 attributes: vec![],
369 version: build_version!(a),
370 has_full_public_key: check_bitmask!(a.flags, 0x0001),
371 public_key_or_token: optional_idx!(blobs, a.public_key_or_token),
372 name: heap_idx!(strings, a.name),
373 culture: optional_idx!(strings, a.culture),
374 hash_value: optional_idx!(blobs, a.hash_value),
375 })
376 })
377 .collect::<Vec<Result<_>>>();
378
379 refs.into_iter().collect::<Result<Vec<_>>>()
380}
381
382fn decode_type_definitions<'a>(
386 tables: &metadata::table::Tables,
387 strings: &StringsReader<'a>,
388 ctx: &convert::read::Context<'_, 'a>,
389) -> Result<Vec<types::TypeDefinition<'a>>> {
390 let mut types = Vec::with_capacity(tables.type_def.len());
391 for (idx, t) in tables.type_def.iter().enumerate() {
392 use types::*;
393
394 let layout_flags = t.flags & 0x18;
395 let name = heap_idx!(strings, t.type_name);
396
397 types.push(TypeDefinition {
398 attributes: vec![],
399 flags: TypeFlags::from_mask(
400 t.flags,
401 if layout_flags == 0x00 {
402 Layout::Automatic
403 } else {
404 let layout = {
405 let pos = tables.class_layout.partition_point(|c| c.parent.0 - 1 < idx);
406 tables.class_layout.get(pos).filter(|c| c.parent.0 - 1 == idx)
407 };
408
409 match layout_flags {
410 0x08 => Layout::Sequential(layout.map(|l| SequentialLayout {
411 packing_size: l.packing_size as usize,
412 class_size: l.class_size as usize,
413 })),
414 0x10 => Layout::Explicit(layout.map(|l| ExplicitLayout {
415 class_size: l.class_size as usize,
416 })),
417 _ => {
418 debug_assert!(false, "unreachable type layout flags outside 0x00/0x08/0x10");
420 unreachable!()
421 },
422 }
423 },
424 ),
425 name,
426 namespace: optional_idx!(strings, t.type_namespace),
427 fields: vec![],
428 properties: vec![],
429 methods: vec![],
430 events: vec![],
431 encloser: None,
432 overrides: vec![],
433 extends: if t.extends.is_null() {
434 None
435 } else {
436 Some(convert::read::type_source(t.extends, ctx)?)
437 },
438 implements: vec![],
439 generic_parameters: vec![],
440 security: None,
441 });
442 }
443
444 Ok(types)
445}
446
447fn decode_files<'a>(
448 tables: &metadata::table::Tables,
449 strings: &StringsReader<'a>,
450 blobs: &BlobReader<'a>,
451) -> Result<Vec<module::File<'a>>> {
452 use rayon::prelude::*;
453
454 let files = tables
455 .file
456 .par_iter()
457 .with_min_len(MIN_PAR_LEN)
458 .map(|f| {
459 Ok(module::File {
460 attributes: vec![],
461 has_metadata: !check_bitmask!(f.flags, 0x0001),
462 name: heap_idx!(strings, f.name),
463 hash_value: heap_idx!(blobs, f.hash_value),
464 })
465 })
466 .collect::<Vec<Result<_>>>();
467
468 files.into_iter().collect::<Result<Vec<_>>>()
469}
470
471fn decode_resources<'a>(
472 dll: &DLL<'a>,
473 tables: &metadata::table::Tables,
474 strings: &StringsReader<'a>,
475 files: &[module::File<'a>],
476 assembly_refs: &[assembly::ExternalAssemblyReference<'a>],
477) -> Result<Vec<resource::ManifestResource<'a>>> {
478 use rayon::prelude::*;
479
480 let resources = tables
481 .manifest_resource
482 .par_iter()
483 .with_min_len(MIN_PAR_LEN)
484 .map(|r| {
485 use metadata::index::Implementation as BinImpl;
486 use resource::*;
487
488 let name = heap_idx!(strings, r.name);
489 let mut offset = r.offset as usize;
490
491 Ok(ManifestResource {
492 attributes: vec![],
493 visibility: match r.flags & 0x7 {
494 0x1 => Visibility::Public,
495 0x2 => Visibility::Private,
496 bad => dll_bail!(validity_bad_flags("manifest resource visibility", bad)),
497 },
498 implementation: match r.implementation {
499 BinImpl::File(f) => {
500 let idx = f - 1;
501 if idx < files.len() {
502 Implementation::File {
503 location: FileIndex(idx),
504 offset,
505 }
506 } else {
507 dll_bail!(resolve_oob(
508 "manifest resource file",
509 idx,
510 files.len().saturating_sub(1),
511 ));
512 }
513 }
514 BinImpl::AssemblyRef(a) => {
515 let idx = a - 1;
516
517 if idx < assembly_refs.len() {
518 Implementation::Assembly {
519 location: AssemblyRefIndex(idx),
520 offset,
521 }
522 } else {
523 dll_bail!(resolve_oob(
524 "manifest resource assembly reference",
525 idx,
526 assembly_refs.len().saturating_sub(1),
527 ));
528 }
529 }
530 BinImpl::ExportedType(_) => {
531 dll_bail!(resolve_bad_target(
532 "manifest resource implementation cannot target ExportedType",
533 ));
534 }
535 BinImpl::Null => {
536 let rva_data = dll.at_rva(&dll.cli.resources)?;
537 let len: u32 = rva_data.gread_with(&mut offset, scroll::LE)?;
538 Implementation::CurrentFile(rva_data[offset..offset + (len as usize)].into())
539 }
540 },
541 name,
542 })
543 })
544 .collect::<Vec<Result<_>>>();
545
546 resources.into_iter().collect::<Result<Vec<_>>>()
547}
548
549fn decode_exported_types<'a>(
550 tables: &metadata::table::Tables,
551 strings: &StringsReader<'a>,
552 files: &[module::File<'a>],
553 assembly_refs: &[assembly::ExternalAssemblyReference<'a>],
554) -> Result<Vec<types::ExportedType<'a>>> {
555 use rayon::prelude::*;
556
557 let exported_types = tables
558 .exported_type
559 .par_iter()
560 .with_min_len(MIN_PAR_LEN)
561 .map(|e| {
562 use metadata::index::Implementation;
563 use types::*;
564
565 let name = heap_idx!(strings, e.type_name);
566 Ok(ExportedType {
567 attributes: vec![],
568 flags: TypeFlags::from_mask(e.flags, Layout::Automatic),
569 namespace: optional_idx!(strings, e.type_namespace),
570 implementation: match e.implementation {
571 Implementation::File(f) => {
572 let idx = f - 1;
573 let t_idx = e.type_def_id as usize;
574
575 if idx < files.len() {
576 TypeImplementation::ModuleFile {
577 type_def: if t_idx < tables.type_def.len() {
578 TypeIndex(t_idx)
579 } else {
580 dll_bail!(resolve_oob(
581 "exported type definition",
582 t_idx,
583 tables.type_def.len().saturating_sub(1),
584 ));
585 },
586 file: FileIndex(idx),
587 }
588 } else {
589 dll_bail!(resolve_oob("exported type file", idx, files.len().saturating_sub(1)));
590 }
591 }
592 Implementation::AssemblyRef(a) => {
593 let idx = a - 1;
594
595 if idx < assembly_refs.len() {
596 TypeImplementation::TypeForwarder(AssemblyRefIndex(idx))
597 } else {
598 dll_bail!(resolve_oob(
599 "exported type assembly reference",
600 idx,
601 assembly_refs.len().saturating_sub(1),
602 ));
603 }
604 }
605 Implementation::ExportedType(t) => {
606 let idx = t - 1;
607 if idx < tables.exported_type.len() {
608 TypeImplementation::Nested(ExportedTypeIndex(idx))
609 } else {
610 dll_bail!(resolve_oob(
611 "exported type nested exported type",
612 idx,
613 tables.exported_type.len().saturating_sub(1),
614 ));
615 }
616 }
617 Implementation::Null => {
618 dll_bail!(resolve_bad_target("exported type implementation cannot be null"));
619 }
620 },
621 name,
622 })
623 })
624 .collect::<Vec<Result<_>>>();
625
626 exported_types.into_iter().collect::<Result<Vec<_>>>()
627}
628
629fn decode_module<'a>(
630 tables: &metadata::table::Tables,
631 strings: &StringsReader<'a>,
632 guids: &GUIDReader<'a>,
633) -> Result<module::Module<'a>> {
634 let module_row = tables
635 .module
636 .first()
637 .ok_or(ParseError::BadStructure("missing required module metadata table"))?;
638 Ok(module::Module {
639 attributes: vec![],
640 name: heap_idx!(strings, module_row.name),
641 mvid: guids.at_index(module_row.mvid)?,
642 })
643}
644
645fn decode_module_refs<'a>(
646 tables: &metadata::table::Tables,
647 strings: &StringsReader<'a>,
648) -> Result<Vec<module::ExternalModuleReference<'a>>> {
649 use rayon::prelude::*;
650
651 let module_refs = tables
652 .module_ref
653 .par_iter()
654 .with_min_len(MIN_PAR_LEN)
655 .map(|r| {
656 Ok(module::ExternalModuleReference {
657 attributes: vec![],
658 name: heap_idx!(strings, r.name),
659 })
660 })
661 .collect::<Vec<Result<_>>>();
662
663 module_refs.into_iter().collect::<Result<Vec<_>>>()
664}
665
666fn decode_type_refs<'a>(
667 tables: &metadata::table::Tables,
668 strings: &StringsReader<'a>,
669 module_refs: &[module::ExternalModuleReference<'a>],
670 assembly_refs: &[assembly::ExternalAssemblyReference<'a>],
671) -> Result<Vec<types::ExternalTypeReference<'a>>> {
672 use rayon::prelude::*;
673
674 let type_refs = tables
675 .type_ref
676 .par_iter()
677 .with_min_len(MIN_PAR_LEN)
678 .map(|r| {
679 use metadata::index::ResolutionScope as BinRS;
680 use types::*;
681
682 let name = heap_idx!(strings, r.type_name);
683 let namespace = optional_idx!(strings, r.type_namespace);
684
685 Ok(ExternalTypeReference {
686 attributes: vec![],
687 namespace,
688 scope: match r.resolution_scope {
689 BinRS::Module(_) => ResolutionScope::CurrentModule,
690 BinRS::ModuleRef(m) => {
691 let idx = m - 1;
692 if idx < module_refs.len() {
693 ResolutionScope::ExternalModule(ModuleRefIndex(idx))
694 } else {
695 dll_bail!(resolve_oob(
696 "type reference module reference",
697 idx,
698 module_refs.len().saturating_sub(1),
699 ));
700 }
701 }
702 BinRS::AssemblyRef(a) => {
703 let idx = a - 1;
704
705 if idx < assembly_refs.len() {
706 ResolutionScope::Assembly(AssemblyRefIndex(idx))
707 } else {
708 dll_bail!(resolve_oob(
709 "type reference assembly reference",
710 idx,
711 assembly_refs.len().saturating_sub(1),
712 ));
713 }
714 }
715 BinRS::TypeRef(t) => {
716 let idx = t - 1;
717 if idx < tables.type_ref.len() {
718 ResolutionScope::Nested(TypeRefIndex(idx))
719 } else {
720 dll_bail!(resolve_oob(
721 "type reference nested type reference",
722 idx,
723 tables.type_ref.len().saturating_sub(1),
724 ));
725 }
726 }
727 BinRS::Null => ResolutionScope::Exported,
728 },
729 name,
730 })
731 })
732 .collect::<Vec<Result<_>>>();
733
734 type_refs.into_iter().collect::<Result<Vec<_>>>()
735}
736
737fn decode_interfaces<'a>(
738 tables: &metadata::table::Tables,
739 types: &mut [types::TypeDefinition<'a>],
740 ctx: &convert::read::Context<'_, 'a>,
741) -> Result<Vec<(usize, usize)>> {
742 let mut interface_idxs = Vec::with_capacity(tables.interface_impl.len());
743 for i in &tables.interface_impl {
744 let idx = i.class.0 - 1;
745 match types.get_mut(idx) {
746 Some(t) => {
747 t.implements
748 .push((vec![], convert::read::type_source(i.interface, ctx)?));
749 interface_idxs.push((idx, t.implements.len() - 1));
750 }
751 None => {
752 dll_bail!(resolve_oob(
753 "interface implementation parent type",
754 idx,
755 types.len().saturating_sub(1),
756 ));
757 }
758 }
759 }
760 Ok(interface_idxs)
761}
762
763fn decode_fields<'a>(
764 types: &mut [types::TypeDefinition<'a>],
765 tables: &metadata::table::Tables,
766 strings: &StringsReader<'a>,
767 blobs: &BlobReader<'a>,
768 ctx: &convert::read::Context<'_, 'a>,
769) -> Result<Vec<FieldIndex>> {
770 use rayon::prelude::*;
771
772 let owned_fields = tables
773 .type_def
774 .iter()
775 .enumerate()
776 .map(|(type_idx, t)| {
777 let start = t.field_list.0 - 1;
778 let end = match tables.type_def.get(type_idx + 1) {
779 Some(next) => next.field_list.0,
780 None => tables.field.len() + 1,
781 } - 1;
782
783 (type_idx, start, end)
784 })
785 .collect::<Vec<_>>();
786
787 let decoded_fields = owned_fields
788 .par_iter()
789 .with_min_len(MIN_PAR_LEN)
790 .map(|&(type_idx, start, end)| {
791 use crate::binary::signature::kinds::FieldSig;
792 use members::*;
793
794 let Some(type_fields) = tables.field.get(start..end) else {
795 dll_bail!(ParseError::BadStructure("invalid field range in TypeDef row"));
796 };
797
798 let mut fields = Vec::with_capacity(type_fields.len());
799 let mut field_idxs = Vec::with_capacity(type_fields.len());
800
801 for (offset, f) in type_fields.iter().enumerate() {
802 let f_idx = start + offset;
803
804 let FieldSig {
805 custom_modifiers: cmod,
806 field_type: t,
807 by_ref,
808 } = heap_idx!(blobs, f.signature).pread(0)?;
809
810 fields.push(Field {
811 attributes: vec![],
812 name: heap_idx!(strings, f.name),
813 type_modifiers: if cmod.is_empty() {
814 vec![]
815 } else {
816 cmod.into_iter()
817 .map(|c| convert::read::custom_modifier(c, ctx))
818 .collect::<Result<_>>()?
819 },
820 by_ref,
821 return_type: MemberType::from_sig(t, ctx)?,
822 accessibility: member_accessibility(f.flags)?,
823 static_member: check_bitmask!(f.flags, 0x10),
824 init_only: check_bitmask!(f.flags, 0x20),
825 literal: check_bitmask!(f.flags, 0x40),
826 default: None,
827 not_serialized: check_bitmask!(f.flags, 0x80),
828 special_name: check_bitmask!(f.flags, 0x200),
829 pinvoke: None,
830 runtime_special_name: check_bitmask!(f.flags, 0x400),
831 offset: None,
832 marshal: None,
833 initial_value: None,
834 });
835
836 field_idxs.push((
837 f_idx,
838 FieldIndex {
839 parent_type: TypeIndex(type_idx),
840 field: fields.len() - 1,
841 },
842 ));
843 }
844
845 Ok((type_idx, fields, field_idxs))
846 })
847 .collect::<Vec<Result<_>>>()
848 .into_iter()
849 .collect::<Result<Vec<_>>>()?;
850
851 build_vec!(fields = FieldIndex[tables.field.len()], {
852 for (type_idx, decoded_type_fields, decoded_type_field_idxs) in decoded_fields {
853 let parent_fields = &mut types[type_idx].fields;
854 let field_offset = parent_fields.len();
855 parent_fields.reserve(decoded_type_fields.len());
856 parent_fields.extend(decoded_type_fields);
857
858 for (f_idx, mut field_idx) in decoded_type_field_idxs {
859 field_idx.field += field_offset;
860 fields[f_idx].write(field_idx);
861 }
862 }
863 });
864
865 Ok(fields)
866}
867
868struct DecodedMethods {
869 methods: Vec<MethodIndex>,
870 owned_params: Vec<(usize, usize, usize)>,
871 sig_pending_def: Vec<(crate::binary::metadata::index::Blob, bool)>,
872}
873
874fn decode_methods<'a>(
878 types: &mut [types::TypeDefinition<'a>],
879 tables: &metadata::table::Tables,
880 strings: &StringsReader<'a>,
881 blobs: &BlobReader<'a>,
882 ctx: &convert::read::Context<'_, 'a>,
883 opts: Options,
884) -> Result<DecodedMethods> {
885 use rayon::prelude::*;
886
887 let owned_methods = tables
888 .type_def
889 .iter()
890 .enumerate()
891 .map(|(type_idx, t)| {
892 let start = t.method_list.0 - 1;
893 let end = match tables.type_def.get(type_idx + 1) {
894 Some(next) => next.method_list.0,
895 None => tables.method_def.len() + 1,
896 } - 1;
897
898 (type_idx, start, end)
899 })
900 .collect::<Vec<_>>();
901
902 let decoded_methods = owned_methods
903 .par_iter()
904 .with_min_len(MIN_PAR_LEN)
905 .map(|&(type_idx, start, end)| {
906 use members::*;
907
908 let Some(type_methods) = tables.method_def.get(start..end) else {
909 dll_bail!(ParseError::BadStructure("invalid method range in TypeDef row"));
910 };
911
912 let mut methods = Vec::with_capacity(type_methods.len());
913 let mut method_idxs = Vec::with_capacity(type_methods.len());
914 let mut param_ranges = Vec::with_capacity(type_methods.len());
915
916 for (offset, m) in type_methods.iter().enumerate() {
917 let m_idx = start + offset;
918
919 let name = heap_idx!(strings, m.name);
920
921 let sig = if opts.lazy_method_signatures {
922 Default::default()
923 } else {
924 let mut sig = convert::read::managed_method(heap_idx!(blobs, m.signature).pread(0)?, ctx)?;
925 if check_bitmask!(m.flags, 0x10) {
926 sig.instance = false;
927 }
928 sig
929 };
930
931 methods.push(Method {
932 attributes: vec![],
933 body: None,
934 signature: sig,
935 accessibility: member_accessibility(m.flags)?,
936 generic_parameters: vec![],
937 return_type_metadata: None,
938 parameter_metadata: vec![],
939 sealed: check_bitmask!(m.flags, 0x20),
940 virtual_member: check_bitmask!(m.flags, 0x40),
941 hide_by_sig: check_bitmask!(m.flags, 0x80),
942 vtable_layout: match m.flags & 0x100 {
943 0x000 => VtableLayout::ReuseSlot,
944 0x100 => VtableLayout::NewSlot,
945 _ => {
946 debug_assert!(false, "unreachable method vtable layout flags");
948 unreachable!()
949 }
950 },
951 strict: check_bitmask!(m.flags, 0x200),
952 abstract_member: check_bitmask!(m.flags, 0x400),
953 special_name: check_bitmask!(m.flags, 0x800),
954 pinvoke: None,
955 runtime_special_name: check_bitmask!(m.flags, 0x1000),
956 security: None,
957 require_sec_object: check_bitmask!(m.flags, 0x8000),
958 body_format: match m.impl_flags & 0x3 {
959 0x0 => BodyFormat::IL,
960 0x1 => BodyFormat::Native,
961 0x2 => {
962 dll_bail!(validity_bad_flags("method implementation code type (OPTIL)", 0x2));
963 }
964 0x3 => BodyFormat::Runtime,
965 _ => {
966 debug_assert!(false, "unreachable method body format flags");
968 unreachable!()
969 }
970 },
971 name,
972 body_management: match m.impl_flags & 0x4 {
973 0x0 => BodyManagement::Unmanaged,
974 0x4 => BodyManagement::Managed,
975 _ => {
976 debug_assert!(false, "unreachable method body-management flags");
978 unreachable!()
979 }
980 },
981 forward_ref: check_bitmask!(m.impl_flags, 0x10),
982 preserve_sig: check_bitmask!(m.impl_flags, 0x80),
983 internal_call: check_bitmask!(m.impl_flags, 0x1000),
984 synchronized: check_bitmask!(m.impl_flags, 0x20),
985 no_inlining: check_bitmask!(m.impl_flags, 0x8),
986 no_optimization: check_bitmask!(m.impl_flags, 0x40),
987 });
988
989 method_idxs.push((
990 m_idx,
991 MethodIndex {
992 parent_type: TypeIndex(type_idx),
993 member: MethodMemberIndex::Method(methods.len() - 1),
994 },
995 ));
996
997 let param_start = m.param_list.0 - 1;
998 let param_end = match tables.method_def.get(m_idx + 1) {
999 Some(next) => next.param_list.0,
1000 None => tables.param.len() + 1,
1001 } - 1;
1002
1003 if tables.param.get(param_start..param_end).is_none() {
1004 dll_bail!(ParseError::BadStructure("invalid parameter range in MethodDef row"));
1005 }
1006
1007 if param_start != param_end {
1008 param_ranges.push((m_idx, param_start, param_end));
1009 }
1010 }
1011
1012 Ok((type_idx, methods, method_idxs, param_ranges))
1013 })
1014 .collect::<Vec<Result<_>>>()
1015 .into_iter()
1016 .collect::<Result<Vec<_>>>()?;
1017
1018 let mut owned_params = Vec::with_capacity(tables.param.len());
1019 let sig_pending_def: Vec<(crate::binary::metadata::index::Blob, bool)> = if opts.lazy_method_signatures {
1020 tables
1021 .method_def
1022 .iter()
1023 .map(|m| (m.signature, check_bitmask!(m.flags, 0x10)))
1024 .collect()
1025 } else {
1026 vec![]
1027 };
1028
1029 build_vec!(methods = MethodIndex[tables.method_def.len()], {
1030 for (type_idx, decoded_type_methods, decoded_type_method_idxs, decoded_type_param_ranges) in decoded_methods {
1031 let parent_methods = &mut types[type_idx].methods;
1032 let method_offset = parent_methods.len();
1033 parent_methods.reserve(decoded_type_methods.len());
1034 parent_methods.extend(decoded_type_methods);
1035
1036 for (m_idx, mut method_idx) in decoded_type_method_idxs {
1037 let MethodMemberIndex::Method(member_idx) = &mut method_idx.member else {
1038 debug_assert!(false, "unreachable decoded method index contained non-method member variant");
1040 unreachable!()
1041 };
1042 *member_idx += method_offset;
1043 methods[m_idx].write(method_idx);
1044 }
1045
1046 owned_params.extend(decoded_type_param_ranges);
1047 }
1048 });
1049
1050 Ok(DecodedMethods {
1051 methods,
1052 owned_params,
1053 sig_pending_def,
1054 })
1055}
1056
1057fn get_field_mut<'a, 'r>(types: &'r mut [types::TypeDefinition<'a>], idx: FieldIndex) -> &'r mut members::Field<'a> {
1058 &mut types[idx.parent_type.0].fields[idx.field]
1059}
1060
1061fn get_method_mut<'a, 'r>(types: &'r mut [types::TypeDefinition<'a>], idx: MethodIndex) -> &'r mut members::Method<'a> {
1065 let MethodMemberIndex::Method(member_idx) = idx.member else {
1066 debug_assert!(false, "unreachable get_method_mut called with non-method member index");
1068 unreachable!()
1069 };
1070 &mut types[idx.parent_type.0].methods[member_idx]
1071}
1072
1073fn decode_params<'a>(
1074 types: &mut [types::TypeDefinition<'a>],
1075 tables: &metadata::table::Tables,
1076 strings: &StringsReader<'a>,
1077 methods: &[MethodIndex],
1078 owned_params: Vec<(usize, usize, usize)>,
1079) -> Result<Vec<(usize, usize)>> {
1080 use rayon::prelude::*;
1081
1082 struct DecodedParam<'a> {
1083 p_idx: usize,
1084 sequence: usize,
1085 metadata: Option<members::ParameterMetadata<'a>>,
1086 }
1087
1088 let decoded_params = owned_params
1089 .par_iter()
1090 .with_min_len(MIN_PAR_LEN)
1091 .map(|&(m_idx, start, end)| {
1092 use members::*;
1093
1094 let mut decoded = Vec::with_capacity(end - start);
1095
1096 for p_idx in start..end {
1097 let param = &tables.param[p_idx];
1098 let sequence = param.sequence as usize;
1099
1100 decoded.push(DecodedParam {
1101 p_idx,
1102 sequence,
1103 metadata: Some(ParameterMetadata {
1104 attributes: vec![],
1105 name: optional_idx!(strings, param.name),
1106 is_in: check_bitmask!(param.flags, 0x1),
1107 is_out: check_bitmask!(param.flags, 0x2),
1108 optional: check_bitmask!(param.flags, 0x10),
1109 default: None,
1110 marshal: None,
1111 }),
1112 });
1113 }
1114
1115 Ok((m_idx, decoded))
1116 })
1117 .collect::<Vec<Result<_>>>()
1118 .into_iter()
1119 .collect::<Result<Vec<_>>>()?;
1120
1121 build_vec!(params = (usize, usize)[tables.param.len()], {
1122 for (m_idx, decoded_method_params) in decoded_params {
1123 let method = get_method_mut(types, methods[m_idx]);
1124
1125 let max_sequence = decoded_method_params
1126 .iter()
1127 .map(|param| param.sequence)
1128 .max()
1129 .unwrap_or(0);
1130 if max_sequence > 0 && method.parameter_metadata.len() < max_sequence {
1131 method.parameter_metadata.resize(max_sequence, None);
1132 }
1133
1134 for param in decoded_method_params {
1135 if param.sequence == 0 {
1136 method.return_type_metadata = param.metadata;
1137 } else {
1138 method.parameter_metadata[param.sequence - 1] = param.metadata;
1139 }
1140
1141 params[param.p_idx].write((m_idx, param.sequence));
1142 }
1143 }
1144 });
1145
1146 Ok(params)
1147}
1148
1149struct DecodedProperties {
1150 properties: Vec<(usize, usize)>,
1151 sig_pending_property: Vec<crate::binary::metadata::index::Blob>,
1152}
1153
1154fn decode_properties<'a>(
1155 types: &mut [types::TypeDefinition<'a>],
1156 tables: &metadata::table::Tables,
1157 strings: &StringsReader<'a>,
1158 blobs: &BlobReader<'a>,
1159 ctx: &convert::read::Context<'_, 'a>,
1160 opts: Options,
1161) -> Result<DecodedProperties> {
1162 use rayon::prelude::*;
1163
1164 let owned_properties = tables
1165 .property_map
1166 .iter()
1167 .enumerate()
1168 .map(|(map_idx, map)| {
1169 let type_idx = map.parent.0 - 1;
1170 if type_idx >= types.len() {
1171 dll_bail!(resolve_oob(
1172 "property map parent type",
1173 type_idx,
1174 types.len().saturating_sub(1),
1175 ));
1176 }
1177
1178 let start = map.property_list.0 - 1;
1179 let end = match tables.property_map.get(map_idx + 1) {
1180 Some(next) => next.property_list.0,
1181 None => tables.property.len() + 1,
1182 } - 1;
1183
1184 Ok((type_idx, start, end, map_idx))
1185 })
1186 .collect::<Vec<Result<_>>>()
1187 .into_iter()
1188 .collect::<Result<Vec<_>>>()?;
1189
1190 let decoded_properties = owned_properties
1191 .par_iter()
1192 .with_min_len(MIN_PAR_LEN)
1193 .map(|&(type_idx, start, end, _map_idx)| {
1194 use crate::binary::signature::kinds::PropertySig;
1195 use members::*;
1196
1197 let Some(props) = tables.property.get(start..end) else {
1198 dll_bail!(ParseError::BadStructure("invalid property range in PropertyMap row"));
1199 };
1200
1201 let mut properties = Vec::with_capacity(props.len());
1202 let mut property_idxs = Vec::with_capacity(props.len());
1203
1204 for (offset, prop) in props.iter().enumerate() {
1205 let p_idx = start + offset;
1206
1207 let (static_member, property_type, parameters) = if opts.lazy_property_signatures {
1208 (
1209 false,
1210 crate::resolved::signature::Parameter::value(MemberType::from_base(
1211 crate::resolved::types::BaseType::Object,
1212 )),
1213 vec![],
1214 )
1215 } else {
1216 let sig = heap_idx!(blobs, prop.property_type).pread::<PropertySig>(0)?;
1217 (!sig.has_this, convert::read::parameter(sig.property_type, ctx)?, {
1218 let mut ps = Vec::with_capacity(sig.params.len());
1219 for p in sig.params {
1220 ps.push(convert::read::parameter(p, ctx)?);
1221 }
1222 ps
1223 })
1224 };
1225
1226 properties.push(Property {
1227 attributes: vec![],
1228 name: heap_idx!(strings, prop.name),
1229 getter: None,
1230 setter: None,
1231 other: vec![],
1232 static_member,
1233 property_type,
1234 parameters,
1235 special_name: check_bitmask!(prop.flags, 0x200),
1236 runtime_special_name: check_bitmask!(prop.flags, 0x1000),
1237 default: None,
1238 });
1239
1240 property_idxs.push((p_idx, (type_idx, properties.len() - 1)));
1241 }
1242
1243 Ok((type_idx, properties, property_idxs))
1244 })
1245 .collect::<Vec<Result<_>>>()
1246 .into_iter()
1247 .collect::<Result<Vec<_>>>()?;
1248
1249 build_vec!(properties = (usize, usize)[tables.property.len()], {
1250 for (type_idx, decoded_type_properties, decoded_type_property_idxs) in decoded_properties {
1251 let parent_properties = &mut types[type_idx].properties;
1252 let property_offset = parent_properties.len();
1253 parent_properties.reserve(decoded_type_properties.len());
1254 parent_properties.extend(decoded_type_properties);
1255
1256 for (p_idx, (prop_type_idx, mut prop_idx)) in decoded_type_property_idxs {
1257 debug_assert_eq!(type_idx, prop_type_idx);
1258 prop_idx += property_offset;
1259 properties[p_idx].write((prop_type_idx, prop_idx));
1260 }
1261 }
1262 });
1263
1264 let sig_pending_property = if opts.lazy_property_signatures {
1265 tables.property.iter().map(|p| p.property_type).collect()
1266 } else {
1267 vec![]
1268 };
1269
1270 Ok(DecodedProperties {
1271 properties,
1272 sig_pending_property,
1273 })
1274}
1275
1276fn decode_events<'a>(
1277 types: &mut [types::TypeDefinition<'a>],
1278 tables: &metadata::table::Tables,
1279 strings: &StringsReader<'a>,
1280 ctx: &convert::read::Context<'_, 'a>,
1281 sem_by_event: &mut HashMap<usize, Vec<(u16, usize)>>,
1282 methods: &mut [MethodIndex],
1283) -> Result<Vec<(usize, usize)>> {
1284 build_vec!(events = (usize, usize)[tables.event.len()], {
1285 for (map_idx, map) in tables.event_map.iter().enumerate() {
1286 let type_idx = map.parent.0 - 1;
1287
1288 let max_type_idx = types.len().saturating_sub(1);
1289 let Some(parent) = types.get_mut(type_idx) else {
1290 dll_bail!(resolve_oob("event map parent type", type_idx, max_type_idx));
1291 };
1292
1293 let start = map.event_list.0 - 1;
1294 let end = match tables.event_map.get(map_idx + 1) {
1295 Some(next) => next.event_list.0,
1296 None => tables.event.len() + 1,
1297 } - 1;
1298
1299 let Some(type_events) = tables.event.get(start..end) else {
1300 dll_bail!(ParseError::BadStructure("invalid event range in EventMap row"));
1301 };
1302
1303 for (offset, event) in type_events.iter().enumerate() {
1304 use members::*;
1305
1306 let e_idx = start + offset;
1307 let name = heap_idx!(strings, event.name);
1308
1309 let internal_idx = parent.events.len();
1310
1311 macro_rules! get_listener {
1312 ($l_name:literal, $flag:literal, $variant:ident) => {{
1313 let Some(entries) = sem_by_event.get_mut(&e_idx) else {
1314 dll_bail!(resolve_missing_row("event listener", e_idx));
1315 };
1316 let Some(position) = entries
1317 .iter()
1318 .position(|(semantics, _)| check_bitmask!(*semantics, $flag))
1319 else {
1320 dll_bail!(resolve_missing_row("event listener", e_idx));
1321 };
1322 let (_, m_idx) = entries.swap_remove(position);
1323 if m_idx < tables.method_def.len() {
1324 let method = extract_method(parent, methods[m_idx], methods, tables)?;
1325 methods[m_idx].member = MethodMemberIndex::$variant(internal_idx);
1326 method
1327 } else {
1328 dll_bail!(resolve_oob(
1329 "event listener method",
1330 m_idx,
1331 tables.method_def.len().saturating_sub(1),
1332 ));
1333 }
1334 }};
1335 }
1336
1337 let add_listener = get_listener!("add", 0x8, EventAdd);
1338 let remove_listener = get_listener!("remove", 0x10, EventRemove);
1339
1340 parent.events.push(Event {
1341 attributes: vec![],
1342 delegate_type: convert::read::type_idx(event.event_type, ctx)?,
1343 add_listener,
1344 remove_listener,
1345 name,
1346 raise_event: None,
1347 other: vec![],
1348 special_name: check_bitmask!(event.event_flags, 0x200),
1349 runtime_special_name: check_bitmask!(event.event_flags, 0x400),
1350 });
1351 events[e_idx].write((type_idx, internal_idx));
1352 }
1353 }
1354 });
1355
1356 Ok(events)
1357}
1358
1359#[derive(Copy, Clone)]
1360enum SemanticsAssociation {
1361 Event(usize),
1362 Property(usize),
1363}
1364
1365#[derive(Copy, Clone)]
1366struct SemanticsAction {
1367 raw_method_idx: usize,
1368 semantics: u16,
1369 association: SemanticsAssociation,
1370}
1371
1372struct TypeSemanticsWork {
1373 parent_type: usize,
1374 method_start: usize,
1375 method_end: usize,
1376 actions: Vec<SemanticsAction>,
1377}
1378
1379fn apply_method_semantics_for_type<'a>(
1380 parent_type: usize,
1381 parent: &mut types::TypeDefinition<'a>,
1382 methods_for_type: &mut [MethodIndex],
1383 method_start: usize,
1384 actions: &[SemanticsAction],
1385 properties: &[(usize, usize)],
1386 events: &[(usize, usize)],
1387) -> Result<()> {
1388 let mut raw_by_internal = vec![usize::MAX; parent.methods.len()];
1389 for (local_raw_idx, method_idx) in methods_for_type.iter().enumerate() {
1390 if let MethodMemberIndex::Method(internal_idx) = method_idx.member {
1391 let Some(slot) = raw_by_internal.get_mut(internal_idx) else {
1392 dll_bail!(resolve_oob(
1393 "method semantics internal method",
1394 internal_idx,
1395 raw_by_internal.len().saturating_sub(1),
1396 ));
1397 };
1398 *slot = local_raw_idx;
1399 }
1400 }
1401
1402 if raw_by_internal.contains(&usize::MAX) {
1403 dll_bail!(resolve_missing_row("method semantics mapping", parent_type));
1404 }
1405
1406 let mut extraction_order = Vec::with_capacity(actions.len());
1407 for (action_idx, action) in actions.iter().enumerate() {
1408 let Some(local_raw_idx) = action
1409 .raw_method_idx
1410 .checked_sub(method_start)
1411 .filter(|idx| *idx < methods_for_type.len())
1412 else {
1413 dll_bail!(resolve_oob(
1414 "method semantics method",
1415 action.raw_method_idx,
1416 method_start + methods_for_type.len().saturating_sub(1),
1417 ));
1418 };
1419
1420 let MethodMemberIndex::Method(internal_idx) = methods_for_type[local_raw_idx].member else {
1421 dll_bail!(resolve_bad_target("method semantics expects method member"));
1422 };
1423
1424 extraction_order.push((internal_idx, action_idx, local_raw_idx));
1425 }
1426 extraction_order.sort_unstable_by_key(|(internal_idx, _, _)| std::cmp::Reverse(*internal_idx));
1427
1428 let mut extracted = Vec::with_capacity(actions.len());
1429
1430 for (internal_idx, action_idx, expected_local_raw_idx) in extraction_order {
1431 let Some(&removed_local_raw_idx) = raw_by_internal.get(internal_idx) else {
1432 dll_bail!(resolve_oob(
1433 "method semantics internal method",
1434 internal_idx,
1435 raw_by_internal.len().saturating_sub(1),
1436 ));
1437 };
1438
1439 if removed_local_raw_idx != expected_local_raw_idx {
1440 dll_bail!(resolve_index_arithmetic("method semantics extraction order mismatch"));
1441 }
1442
1443 let moved_local_raw_idx = raw_by_internal[raw_by_internal.len() - 1];
1444
1445 raw_by_internal.swap_remove(internal_idx);
1446 let method = parent.methods.swap_remove(internal_idx);
1447
1448 if internal_idx < raw_by_internal.len() {
1449 methods_for_type[moved_local_raw_idx].member = MethodMemberIndex::Method(internal_idx);
1450 }
1451
1452 extracted.push((action_idx, method));
1453 }
1454
1455 extracted.sort_unstable_by_key(|(action_idx, _)| *action_idx);
1456
1457 for ((expected_action_idx, action), (action_idx, new_meth)) in actions.iter().enumerate().zip(extracted) {
1458 debug_assert_eq!(expected_action_idx, action_idx);
1459
1460 let Some(local_raw_idx) = action
1461 .raw_method_idx
1462 .checked_sub(method_start)
1463 .filter(|idx| *idx < methods_for_type.len())
1464 else {
1465 dll_bail!(resolve_oob(
1466 "method semantics method",
1467 action.raw_method_idx,
1468 method_start + methods_for_type.len().saturating_sub(1),
1469 ));
1470 };
1471
1472 let member_idx = &mut methods_for_type[local_raw_idx].member;
1473
1474 match action.association {
1475 SemanticsAssociation::Event(idx) => {
1476 let &(_, internal_idx) = events
1477 .get(idx)
1478 .ok_or_else(|| resolve_oob("method semantics event", idx, events.len().saturating_sub(1)))?;
1479 let event = &mut parent.events[internal_idx];
1480
1481 if check_bitmask!(action.semantics, 0x20) {
1482 event.raise_event = Some(new_meth);
1483 *member_idx = MethodMemberIndex::EventRaise(internal_idx);
1484 } else if check_bitmask!(action.semantics, 0x4) {
1485 event.other.push(new_meth);
1486 *member_idx = MethodMemberIndex::EventOther {
1487 event: internal_idx,
1488 other: event.other.len() - 1,
1489 };
1490 }
1491 }
1492 SemanticsAssociation::Property(idx) => {
1493 let &(_, internal_idx) = properties.get(idx).ok_or_else(|| {
1494 resolve_oob(
1495 "method semantics property",
1496 idx,
1497 properties.len().saturating_sub(1),
1498 )
1499 })?;
1500 let property = &mut parent.properties[internal_idx];
1501
1502 if check_bitmask!(action.semantics, 0x1) {
1503 property.setter = Some(new_meth);
1504 *member_idx = MethodMemberIndex::PropertySetter(internal_idx);
1505 } else if check_bitmask!(action.semantics, 0x2) {
1506 property.getter = Some(new_meth);
1507 *member_idx = MethodMemberIndex::PropertyGetter(internal_idx);
1508 } else if check_bitmask!(action.semantics, 0x4) {
1509 property.other.push(new_meth);
1510 *member_idx = MethodMemberIndex::PropertyOther {
1511 property: internal_idx,
1512 other: property.other.len() - 1,
1513 };
1514 }
1515 }
1516 }
1517 }
1518
1519 Ok(())
1520}
1521
1522fn apply_method_semantics_work<'a>(
1523 types: &mut [types::TypeDefinition<'a>],
1524 methods: &mut [MethodIndex],
1525 works: &[TypeSemanticsWork],
1526 type_base: usize,
1527 method_base: usize,
1528 properties: &[(usize, usize)],
1529 events: &[(usize, usize)],
1530) -> Result<()> {
1531 if works.is_empty() {
1532 return Ok(());
1533 }
1534
1535 const SEQUENTIAL_WORK_THRESHOLD: usize = 8;
1536
1537 if works.len() <= SEQUENTIAL_WORK_THRESHOLD {
1538 for work in works {
1539 let Some(type_local_idx) = work.parent_type.checked_sub(type_base).filter(|idx| *idx < types.len()) else {
1540 dll_bail!(resolve_oob(
1541 "method semantics parent type",
1542 work.parent_type,
1543 type_base + types.len().saturating_sub(1),
1544 ));
1545 };
1546
1547 let Some(method_start) = work
1548 .method_start
1549 .checked_sub(method_base)
1550 .filter(|idx| *idx <= methods.len())
1551 else {
1552 dll_bail!(resolve_oob(
1553 "method semantics start index",
1554 work.method_start,
1555 method_base + methods.len(),
1556 ));
1557 };
1558
1559 let Some(method_end) = work
1560 .method_end
1561 .checked_sub(method_base)
1562 .filter(|idx| *idx <= methods.len())
1563 else {
1564 dll_bail!(resolve_oob(
1565 "method semantics end index",
1566 work.method_end,
1567 method_base + methods.len(),
1568 ));
1569 };
1570
1571 let parent = &mut types[type_local_idx];
1572 let methods_for_type = methods
1573 .get_mut(method_start..method_end)
1574 .ok_or_else(|| resolve_index_arithmetic("invalid method range for method semantics"))?;
1575
1576 apply_method_semantics_for_type(
1577 work.parent_type,
1578 parent,
1579 methods_for_type,
1580 work.method_start,
1581 &work.actions,
1582 properties,
1583 events,
1584 )?;
1585 }
1586
1587 return Ok(());
1588 }
1589
1590 let mid = works.len() / 2;
1591 let split_type = works[mid]
1592 .parent_type
1593 .checked_sub(type_base)
1594 .ok_or_else(|| resolve_index_arithmetic("invalid type split for method semantics"))?;
1595 let split_method = works[mid]
1596 .method_start
1597 .checked_sub(method_base)
1598 .ok_or_else(|| resolve_index_arithmetic("invalid method split for method semantics"))?;
1599
1600 let (left_types, right_types) = types.split_at_mut(split_type);
1601 let (left_methods, right_methods) = methods.split_at_mut(split_method);
1602 let (left_works, right_works) = works.split_at(mid);
1603
1604 let (left_result, right_result) = rayon::join(
1605 || {
1606 apply_method_semantics_work(
1607 left_types,
1608 left_methods,
1609 left_works,
1610 type_base,
1611 method_base,
1612 properties,
1613 events,
1614 )
1615 },
1616 || {
1617 apply_method_semantics_work(
1618 right_types,
1619 right_methods,
1620 right_works,
1621 type_base + split_type,
1622 method_base + split_method,
1623 properties,
1624 events,
1625 )
1626 },
1627 );
1628
1629 left_result?;
1630 right_result
1631}
1632
1633fn apply_method_semantics<'a>(
1634 types: &mut [types::TypeDefinition<'a>],
1635 tables: &metadata::table::Tables,
1636 methods: &mut [MethodIndex],
1637 properties: &[(usize, usize)],
1638 events: &[(usize, usize)],
1639 sem_by_event: &HashMap<usize, Vec<(u16, usize)>>,
1640 sem_by_property: &HashMap<usize, Vec<(u16, usize)>>,
1641) -> Result<()> {
1642 let mut remaining_event_counts: HashMap<(usize, u16, usize), usize> =
1646 HashMap::with_capacity_and_hasher(tables.method_semantics.len(), Default::default());
1647 let mut remaining_property_counts: HashMap<(usize, u16, usize), usize> =
1648 HashMap::with_capacity_and_hasher(tables.method_semantics.len(), Default::default());
1649
1650 for (&event_idx, entries) in sem_by_event {
1651 for &(semantics, raw_method_idx) in entries {
1652 *remaining_event_counts
1653 .entry((event_idx, semantics, raw_method_idx))
1654 .or_insert(0) += 1;
1655 }
1656 }
1657
1658 for (&property_idx, entries) in sem_by_property {
1659 for &(semantics, raw_method_idx) in entries {
1660 *remaining_property_counts
1661 .entry((property_idx, semantics, raw_method_idx))
1662 .or_insert(0) += 1;
1663 }
1664 }
1665
1666 let mut semantics_by_type: HashMap<usize, Vec<SemanticsAction>> =
1667 HashMap::with_capacity_and_hasher(types.len(), Default::default());
1668
1669 for s in &tables.method_semantics {
1670 use metadata::index::HasSemantics;
1671
1672 let raw_method_idx = s.method.0 - 1;
1673
1674 let (association, include) = match s.association {
1675 HasSemantics::Event(i) => {
1676 let idx = i - 1;
1677 let key = (idx, s.semantics, raw_method_idx);
1678 let include = match remaining_event_counts.get_mut(&key) {
1679 Some(count) if *count > 0 => {
1680 *count -= 1;
1681 true
1682 }
1683 _ => false,
1684 };
1685 (SemanticsAssociation::Event(idx), include)
1686 }
1687 HasSemantics::Property(i) => {
1688 let idx = i - 1;
1689 let key = (idx, s.semantics, raw_method_idx);
1690 let include = match remaining_property_counts.get_mut(&key) {
1691 Some(count) if *count > 0 => {
1692 *count -= 1;
1693 true
1694 }
1695 _ => false,
1696 };
1697 (SemanticsAssociation::Property(idx), include)
1698 }
1699 HasSemantics::Null => {
1700 dll_bail!(resolve_bad_target("method semantics association cannot be null"));
1701 }
1702 };
1703
1704 if !include {
1705 continue;
1706 }
1707
1708 let Some(&method_idx) = methods.get(raw_method_idx) else {
1709 dll_bail!(resolve_oob(
1710 "method semantics method",
1711 raw_method_idx,
1712 methods.len().saturating_sub(1),
1713 ));
1714 };
1715
1716 semantics_by_type
1717 .entry(method_idx.parent_type.0)
1718 .or_default()
1719 .push(SemanticsAction {
1720 raw_method_idx,
1721 semantics: s.semantics,
1722 association,
1723 });
1724 }
1725
1726 let mut work_by_type = semantics_by_type
1727 .into_iter()
1728 .map(|(parent_type, actions)| {
1729 let type_idx = TypeIndex(parent_type);
1730 let method_start = methods.partition_point(|m| m.parent_type < type_idx);
1731 let method_end = methods.partition_point(|m| m.parent_type <= type_idx);
1732
1733 TypeSemanticsWork {
1734 parent_type,
1735 method_start,
1736 method_end,
1737 actions,
1738 }
1739 })
1740 .collect::<Vec<_>>();
1741 work_by_type.sort_unstable_by_key(|work| work.parent_type);
1742
1743 apply_method_semantics_work(types, methods, &work_by_type, 0, 0, properties, events)
1744}
1745
1746struct DecodedMemberRefs<'a> {
1747 field_refs: Vec<members::ExternalFieldReference<'a>>,
1748 field_map: HashMap<usize, usize>,
1749 method_refs: Vec<members::ExternalMethodReference<'a>>,
1750 method_map: HashMap<usize, usize>,
1751 sig_pending_ref: Vec<crate::binary::metadata::index::Blob>,
1752}
1753
1754enum DecodedMemberRef<'a> {
1755 Field(members::ExternalFieldReference<'a>),
1756 Method {
1757 method_ref: members::ExternalMethodReference<'a>,
1758 blob_idx: Option<crate::binary::metadata::index::Blob>,
1759 },
1760 Skip,
1761}
1762
1763fn decode_member_refs<'a>(
1767 tables: &metadata::table::Tables,
1768 strings: &StringsReader<'a>,
1769 blobs: &BlobReader<'a>,
1770 module_refs: &[module::ExternalModuleReference<'a>],
1771 methods: &[MethodIndex],
1772 ctx: &convert::read::Context<'_, 'a>,
1773 opts: Options,
1774) -> Result<DecodedMemberRefs<'a>> {
1775 use rayon::prelude::*;
1776
1777 let decoded = tables
1778 .member_ref
1779 .par_iter()
1780 .with_min_len(MIN_PAR_LEN)
1781 .map(|r| {
1782 use members::*;
1783 use metadata::index::{MemberRefParent, TypeDefOrRef};
1784
1785 let name = strings.at_index(r.name)?.into();
1786 let sig_blob = blobs.at_index(r.signature)?;
1787
1788 let Some(&sig_kind) = sig_blob.first() else {
1789 return Ok(DecodedMemberRef::Skip);
1790 };
1791
1792 if sig_kind == 0x06 {
1793 use crate::binary::signature::kinds::FieldSig;
1794
1795 let field_sig: FieldSig = match sig_blob.pread(0) {
1797 Ok(s) => s,
1798 Err(_) => return Ok(DecodedMemberRef::Skip),
1799 };
1800
1801 let parent = match r.class {
1802 MemberRefParent::TypeDef(i) => {
1803 FieldReferenceParent::Type(convert::read::type_idx(TypeDefOrRef::TypeDef(i), ctx)?)
1804 }
1805 MemberRefParent::TypeRef(i) => {
1806 FieldReferenceParent::Type(convert::read::type_idx(TypeDefOrRef::TypeRef(i), ctx)?)
1807 }
1808 MemberRefParent::TypeSpec(i) => {
1809 FieldReferenceParent::Type(convert::read::type_idx(TypeDefOrRef::TypeSpec(i), ctx)?)
1810 }
1811 MemberRefParent::ModuleRef(i) => {
1812 let idx = i - 1;
1813 if idx < module_refs.len() {
1814 FieldReferenceParent::Module(ModuleRefIndex(idx))
1815 } else {
1816 dll_bail!(resolve_oob(
1817 "field reference module reference",
1818 idx,
1819 module_refs.len().saturating_sub(1),
1820 ));
1821 }
1822 }
1823 _ => return Ok(DecodedMemberRef::Skip),
1824 };
1825
1826 let field_type = MemberType::from_sig(field_sig.field_type, ctx)?;
1827 let mut custom_modifiers = Vec::with_capacity(field_sig.custom_modifiers.len());
1828 for c in field_sig.custom_modifiers {
1829 custom_modifiers.push(convert::read::custom_modifier(c, ctx)?);
1830 }
1831
1832 Ok(DecodedMemberRef::Field(ExternalFieldReference {
1833 attributes: vec![],
1834 parent,
1835 name,
1836 custom_modifiers,
1837 field_type,
1838 }))
1839 } else {
1840 use crate::binary::signature::kinds::{CallingConvention, MethodRefSig};
1841
1842 let (signature, blob_idx) = if opts.lazy_method_signatures {
1843 (Default::default(), Some(r.signature))
1844 } else {
1845 let ref_sig: MethodRefSig = match sig_blob.pread(0) {
1847 Ok(s) => s,
1848 Err(_) => return Ok(DecodedMemberRef::Skip),
1849 };
1850
1851 let mut sig = convert::read::managed_method(ref_sig.method_def, ctx)?;
1852 if sig.calling_convention == CallingConvention::Vararg {
1853 let mut varargs = Vec::with_capacity(ref_sig.varargs.len());
1854 for p in ref_sig.varargs {
1855 varargs.push(convert::read::parameter(p, ctx)?);
1856 }
1857 sig.varargs = Some(varargs);
1858 }
1859 (sig, None)
1860 };
1861
1862 let parent = match r.class {
1863 MemberRefParent::TypeDef(i) => {
1864 MethodReferenceParent::Type(convert::read::type_idx(TypeDefOrRef::TypeDef(i), ctx)?)
1865 }
1866 MemberRefParent::TypeRef(i) => {
1867 MethodReferenceParent::Type(convert::read::type_idx(TypeDefOrRef::TypeRef(i), ctx)?)
1868 }
1869 MemberRefParent::TypeSpec(i) => {
1870 MethodReferenceParent::Type(convert::read::type_idx(TypeDefOrRef::TypeSpec(i), ctx)?)
1871 }
1872 MemberRefParent::ModuleRef(i) => {
1873 let idx = i - 1;
1874 if idx < module_refs.len() {
1875 MethodReferenceParent::Module(ModuleRefIndex(idx))
1876 } else {
1877 dll_bail!(resolve_oob(
1878 "method reference module reference",
1879 idx,
1880 module_refs.len().saturating_sub(1),
1881 ));
1882 }
1883 }
1884 MemberRefParent::MethodDef(i) => {
1885 let idx = i - 1;
1886 match methods.get(idx) {
1887 Some(&m) => MethodReferenceParent::VarargMethod(m),
1888 None => {
1889 dll_bail!(resolve_oob(
1890 "method reference method definition",
1891 idx,
1892 methods.len().saturating_sub(1),
1893 ));
1894 }
1895 }
1896 }
1897 MemberRefParent::Null => {
1898 dll_bail!(resolve_bad_target("method reference parent cannot be null"));
1899 }
1900 };
1901
1902 Ok(DecodedMemberRef::Method {
1903 method_ref: ExternalMethodReference {
1904 attributes: vec![],
1905 parent,
1906 name,
1907 signature,
1908 },
1909 blob_idx,
1910 })
1911 }
1912 })
1913 .collect::<Vec<Result<_>>>();
1914 let decoded = decoded.into_iter().collect::<Result<Vec<_>>>()?;
1915
1916 let member_ref_len = tables.member_ref.len();
1917 let mut field_refs = Vec::with_capacity(member_ref_len);
1918 let mut field_map = HashMap::with_capacity_and_hasher(member_ref_len, Default::default());
1919 let mut method_refs = Vec::with_capacity(member_ref_len);
1920 let mut method_map = HashMap::with_capacity_and_hasher(member_ref_len, Default::default());
1921 let mut sig_pending_ref: Vec<crate::binary::metadata::index::Blob> = if opts.lazy_method_signatures {
1922 Vec::with_capacity(member_ref_len)
1923 } else {
1924 vec![]
1925 };
1926
1927 for (orig_idx, decoded_ref) in decoded.into_iter().enumerate() {
1928 match decoded_ref {
1929 DecodedMemberRef::Field(field_ref) => {
1930 let current_idx = field_refs.len();
1931 field_map.insert(orig_idx, current_idx);
1932 field_refs.push(field_ref);
1933 }
1934 DecodedMemberRef::Method { method_ref, blob_idx } => {
1935 let current_idx = method_refs.len();
1936 method_map.insert(orig_idx, current_idx);
1937 if let Some(blob_idx) = blob_idx {
1938 sig_pending_ref.push(blob_idx);
1939 }
1940 method_refs.push(method_ref);
1941 }
1942 DecodedMemberRef::Skip => {}
1943 }
1944 }
1945
1946 Ok(DecodedMemberRefs {
1947 field_refs,
1948 field_map,
1949 method_refs,
1950 method_map,
1951 sig_pending_ref,
1952 })
1953}
1954
1955#[allow(clippy::too_many_lines, clippy::nonminimal_bool)]
1956pub(crate) fn read_impl<'a>(dll: &DLL<'a>, opts: Options) -> Result<Resolution<'a>> {
1957 let (strings, blobs, guids, userstrings, logical) = dll.get_all_streams()?;
1958 let tables = logical.tables;
1959
1960 let def_len = tables.type_def.len();
1961 let ref_len = tables.type_ref.len();
1962 let ctx = convert::read::Context {
1963 def_len,
1964 ref_len,
1965 specs: &tables.type_spec,
1966 sigs: &tables.stand_alone_sig,
1967 blobs: &blobs,
1968 userstrings: &userstrings,
1969 };
1970
1971 stage_start!(stage_timer);
1972 debug!("assembly");
1973 let mut assembly = decode_assembly(&tables, &strings, &blobs)?;
1974 stage_end!(stage_timer, "assembly");
1975
1976 stage_start!(stage_timer);
1977 debug!("assembly refs");
1978 let assembly_refs = decode_assembly_refs(&tables, &strings, &blobs)?;
1979 stage_end!(stage_timer, "assembly refs");
1980
1981 stage_start!(stage_timer);
1982 debug!("type definitions");
1983 let mut types = decode_type_definitions(&tables, &strings, &ctx)?;
1984 stage_end!(stage_timer, "type definitions");
1985
1986 debug!("nested types");
1987
1988 for n in &tables.nested_class {
1989 let nest_idx = n.nested_class.0 - 1;
1990 match types.get_mut(nest_idx) {
1991 Some(t) => {
1992 let enclose_idx = n.enclosing_class.0 - 1;
1993 if enclose_idx < tables.type_def.len() {
1994 t.encloser = Some(TypeIndex(enclose_idx));
1995 } else {
1996 dll_bail!(resolve_oob(
1997 "nested class enclosing type",
1998 enclose_idx,
1999 tables.type_def.len().saturating_sub(1),
2000 ));
2001 }
2002 }
2003 None => {
2004 dll_bail!(resolve_oob(
2005 "nested class type",
2006 nest_idx,
2007 types.len().saturating_sub(1),
2008 ));
2009 }
2010 }
2011 }
2012
2013 debug!("files");
2014 let files = decode_files(&tables, &strings, &blobs)?;
2015
2016 debug!("resources");
2017 let resources = decode_resources(dll, &tables, &strings, &files, &assembly_refs)?;
2018
2019 debug!("exported types");
2020 let exports = decode_exported_types(&tables, &strings, &files, &assembly_refs)?;
2021
2022 let module = decode_module(&tables, &strings, &guids)?;
2023
2024 debug!("resolving module {}", module.name);
2025
2026 let module_refs = decode_module_refs(&tables, &strings)?;
2027
2028 debug!("type refs");
2029 let type_refs = decode_type_refs(&tables, &strings, &module_refs, &assembly_refs)?;
2030
2031 debug!("interfaces");
2032 let interface_idxs = decode_interfaces(&tables, &mut types, &ctx)?;
2033
2034 stage_start!(stage_timer);
2035 debug!("fields");
2036 let fields = decode_fields(&mut types, &tables, &strings, &blobs, &ctx)?;
2037 stage_end!(stage_timer, "fields");
2038
2039 debug!("field layout");
2040
2041 {
2042 use rayon::prelude::*;
2043
2044 let field_layout_updates = tables
2045 .field_layout
2046 .par_iter()
2047 .with_min_len(MIN_PAR_LEN)
2048 .map(|layout| {
2049 let idx = layout.field.0 - 1;
2050 match fields.get(idx) {
2051 Some(&field) => Ok((field, layout.offset as usize)),
2052 None => Err(resolve_oob(
2053 "field layout parent field",
2054 idx,
2055 fields.len().saturating_sub(1),
2056 )),
2057 }
2058 })
2059 .collect::<Vec<Result<_>>>()
2060 .into_iter()
2061 .collect::<Result<Vec<_>>>()?;
2062
2063 for (field, offset) in field_layout_updates {
2064 get_field_mut(&mut types, field).offset = Some(offset);
2065 }
2066 }
2067
2068 debug!("field rva");
2069
2070 {
2071 use rayon::prelude::*;
2072
2073 let field_rva_updates = tables
2074 .field_rva
2075 .par_iter()
2076 .with_min_len(MIN_PAR_LEN)
2077 .map(|rva| {
2078 let idx = rva.field.0 - 1;
2079 match fields.get(idx) {
2080 Some(&field) => Ok((field, dll.raw_rva(rva.rva)?.into())),
2081 None => Err(resolve_oob(
2082 "field RVA parent field",
2083 idx,
2084 fields.len().saturating_sub(1),
2085 )),
2086 }
2087 })
2088 .collect::<Vec<Result<_>>>()
2089 .into_iter()
2090 .collect::<Result<Vec<_>>>()?;
2091
2092 for (field, initial_value) in field_rva_updates {
2093 get_field_mut(&mut types, field).initial_value = Some(initial_value);
2094 }
2095 }
2096
2097 stage_start!(stage_timer);
2098 debug!("methods");
2099 let DecodedMethods {
2100 mut methods,
2101 owned_params,
2102 sig_pending_def,
2103 } = decode_methods(&mut types, &tables, &strings, &blobs, &ctx, opts)?;
2104 stage_end!(stage_timer, "methods");
2105
2106 macro_rules! get_method {
2109 ($unwrap:expr) => {{
2110 let MethodIndex { parent_type, member } = $unwrap;
2111 &mut types[parent_type.0].methods[match member {
2112 MethodMemberIndex::Method(i) => i,
2113 _ => {
2114 debug_assert!(false, "unreachable get_method! saw non-method member variant");
2117 unreachable!()
2118 }
2119 }]
2120 }};
2121 }
2122
2123 debug!("pinvoke");
2124
2125 {
2126 use members::*;
2127 use metadata::index::MemberForwarded;
2128 use rayon::prelude::*;
2129
2130 enum PInvokeTarget {
2131 Field(FieldIndex),
2132 Method(MethodIndex),
2133 }
2134
2135 let pinvoke_updates = tables
2136 .impl_map
2137 .par_iter()
2138 .with_min_len(MIN_PAR_LEN)
2139 .map(|i| {
2140 let name = heap_idx!(strings, i.import_name);
2141
2142 let value = PInvoke {
2143 no_mangle: check_bitmask!(i.mapping_flags, 0x1),
2144 character_set: match i.mapping_flags & 0x6 {
2145 0x0 => CharacterSet::NotSpecified,
2146 0x2 => CharacterSet::Ansi,
2147 0x4 => CharacterSet::Unicode,
2148 0x6 => CharacterSet::Auto,
2149 bad => {
2150 dll_bail!(validity_bad_flags("PInvoke character set specifier", u32::from(bad)));
2151 }
2152 },
2153 supports_last_error: check_bitmask!(i.mapping_flags, 0x40),
2154 calling_convention: match i.mapping_flags & 0x700 {
2155 0x100 => UnmanagedCallingConvention::Platformapi,
2156 0x200 => UnmanagedCallingConvention::Cdecl,
2157 0x300 => UnmanagedCallingConvention::Stdcall,
2158 0x400 => UnmanagedCallingConvention::Thiscall,
2159 0x500 => UnmanagedCallingConvention::Fastcall,
2160 bad => {
2161 dll_bail!(validity_bad_flags(
2162 "PInvoke calling convention specifier",
2163 u32::from(bad),
2164 ));
2165 }
2166 },
2167 import_name: name.clone(),
2168 import_scope: {
2169 let idx = i.import_scope.0 - 1;
2170
2171 if idx < module_refs.len() {
2172 ModuleRefIndex(idx)
2173 } else {
2174 dll_bail!(resolve_oob(
2175 "PInvoke import scope module reference",
2176 idx,
2177 module_refs.len().saturating_sub(1),
2178 ));
2179 }
2180 },
2181 };
2182
2183 let target = match i.member_forwarded {
2184 MemberForwarded::Field(i) => {
2185 let idx = i - 1;
2186
2187 match fields.get(idx) {
2188 Some(&i) => PInvokeTarget::Field(i),
2189 None => {
2190 dll_bail!(resolve_oob(
2191 "PInvoke forwarded field",
2192 idx,
2193 fields.len().saturating_sub(1),
2194 ));
2195 }
2196 }
2197 }
2198 MemberForwarded::MethodDef(i) => {
2199 let idx = i - 1;
2200
2201 match methods.get(idx) {
2202 Some(&m) => PInvokeTarget::Method(m),
2203 None => {
2204 dll_bail!(resolve_oob(
2205 "PInvoke forwarded method",
2206 idx,
2207 methods.len().saturating_sub(1),
2208 ));
2209 }
2210 }
2211 }
2212 MemberForwarded::Null => {
2213 dll_bail!(resolve_bad_target("PInvoke member_forwarded cannot be null"));
2214 }
2215 };
2216
2217 Ok((target, value))
2218 })
2219 .collect::<Vec<Result<_>>>()
2220 .into_iter()
2221 .collect::<Result<Vec<_>>>()?;
2222
2223 for (target, value) in pinvoke_updates {
2224 match target {
2225 PInvokeTarget::Field(field) => get_field_mut(&mut types, field).pinvoke = Some(value),
2226 PInvokeTarget::Method(method) => get_method!(method).pinvoke = Some(value),
2227 }
2228 }
2229 }
2230
2231 debug!("security");
2232
2233 for s in &tables.decl_security {
2234 use attribute::*;
2235 use metadata::index::HasDeclSecurity;
2236
2237 let parent = match s.parent {
2238 HasDeclSecurity::TypeDef(t) => {
2239 let t_idx = t - 1;
2240 match types.get_mut(t_idx) {
2241 Some(t) => &mut t.security,
2242 None => {
2243 dll_bail!(resolve_oob(
2244 "security declaration type parent",
2245 t_idx,
2246 types.len().saturating_sub(1),
2247 ));
2248 }
2249 }
2250 }
2251 HasDeclSecurity::MethodDef(m) => {
2252 let m_idx = m - 1;
2253 match methods.get(m_idx) {
2254 Some(&m) => &mut get_method!(m).security,
2255 None => {
2256 dll_bail!(resolve_oob(
2257 "security declaration method parent",
2258 m_idx,
2259 methods.len().saturating_sub(1),
2260 ));
2261 }
2262 }
2263 }
2264 HasDeclSecurity::Assembly(_) => match &mut assembly {
2265 Some(a) => &mut a.security,
2266 None => dll_bail!(resolve_missing_row("Assembly", 0)),
2267 },
2268 HasDeclSecurity::Null => {
2269 dll_bail!(resolve_bad_target("security declaration parent cannot be null"));
2270 }
2271 };
2272
2273 *parent = Some(SecurityDeclaration {
2274 attributes: vec![],
2275 action: s.action,
2276 value: heap_idx!(blobs, s.permission_set),
2277 });
2278 }
2279
2280 debug!("generic parameters");
2281
2282 let mut constraint_map =
2283 HashMap::with_capacity_and_hasher(tables.generic_param_constraint.len(), Default::default());
2284
2285 for (param_idx, p) in tables.generic_param.iter().enumerate() {
2288 use metadata::index::TypeOrMethodDef;
2289
2290 let name = heap_idx!(strings, p.name);
2291
2292 match p.owner {
2293 TypeOrMethodDef::TypeDef(i) => {
2294 let idx = i - 1;
2295 match types.get_mut(idx) {
2296 Some(t) => {
2297 t.generic_parameters.push(make_generic(
2298 name,
2299 p,
2300 param_idx,
2301 &mut constraint_map,
2302 &tables,
2303 &ctx,
2304 )?);
2305 }
2306 None => {
2307 dll_bail!(resolve_oob(
2308 "generic parameter type owner",
2309 idx,
2310 types.len().saturating_sub(1),
2311 ));
2312 }
2313 }
2314 }
2315 TypeOrMethodDef::MethodDef(i) => {
2316 let idx = i - 1;
2317 let method = match methods.get(idx) {
2318 Some(&m) => get_method!(m),
2319 None => {
2320 dll_bail!(resolve_oob(
2321 "generic parameter method owner",
2322 idx,
2323 methods.len().saturating_sub(1),
2324 ));
2325 }
2326 };
2327
2328 method
2329 .generic_parameters
2330 .push(make_generic(name, p, param_idx, &mut constraint_map, &tables, &ctx)?);
2331 }
2332 TypeOrMethodDef::Null => {
2333 dll_bail!(resolve_bad_target("generic parameter owner cannot be null"));
2334 }
2335 }
2336 }
2337
2338 stage_start!(stage_timer);
2339 debug!("params");
2340 let params = decode_params(&mut types, &tables, &strings, &methods, owned_params)?;
2341 stage_end!(stage_timer, "params");
2342
2343 debug!("field marshal");
2344
2345 {
2346 use crate::binary::{metadata::index::HasFieldMarshal, signature::kinds::MarshalSpec};
2347 use rayon::prelude::*;
2348
2349 let field_marshal_updates = tables
2350 .field_marshal
2351 .par_iter()
2352 .with_min_len(MIN_PAR_LEN)
2353 .filter_map(|marshal| match marshal.parent {
2354 HasFieldMarshal::Field(_) => Some(marshal),
2355 _ => None,
2356 })
2357 .map(|marshal| {
2358 let idx = match marshal.parent {
2359 HasFieldMarshal::Field(i) => i - 1,
2360 _ => {
2361 debug_assert!(false, "unreachable field_marshal update with non-field parent");
2363 unreachable!()
2364 }
2365 };
2366 match fields.get(idx) {
2367 Some(&field) => Ok((field, heap_idx!(blobs, marshal.native_type).pread::<MarshalSpec>(0)?)),
2368 None => Err(resolve_oob("field marshal field", idx, fields.len().saturating_sub(1))),
2369 }
2370 })
2371 .collect::<Vec<Result<_>>>()
2372 .into_iter()
2373 .collect::<Result<Vec<_>>>()?;
2374
2375 for (field, marshal) in field_marshal_updates {
2376 get_field_mut(&mut types, field).marshal = Some(marshal);
2377 }
2378
2379 for marshal in &tables.field_marshal {
2380 match marshal.parent {
2381 HasFieldMarshal::Field(_) => {}
2382 HasFieldMarshal::Param(i) => {
2383 let value = Some(heap_idx!(blobs, marshal.native_type).pread::<MarshalSpec>(0)?);
2384 let idx = i - 1;
2385 match params.get(idx) {
2386 Some(&(m_idx, p_idx)) => {
2387 let method = get_method!(methods[m_idx]);
2388
2389 let param_meta = if p_idx == 0 {
2390 &mut method.return_type_metadata
2391 } else {
2392 &mut method.parameter_metadata[p_idx - 1]
2393 };
2394
2395 param_meta
2396 .as_mut()
2397 .ok_or(ResolveError::MissingRow {
2398 table: "Param",
2399 index: idx,
2400 })?
2401 .marshal = value;
2402 }
2403 None => {
2404 dll_bail!(resolve_oob(
2405 "field marshal parameter",
2406 idx,
2407 params.len().saturating_sub(1),
2408 ));
2409 }
2410 }
2411 }
2412 HasFieldMarshal::Null => {
2413 dll_bail!(resolve_bad_target("field marshal parent cannot be null"));
2414 }
2415 }
2416 }
2417 }
2418
2419 stage_start!(stage_timer);
2420 debug!("properties");
2421 let DecodedProperties {
2422 properties,
2423 sig_pending_property,
2424 } = decode_properties(&mut types, &tables, &strings, &blobs, &ctx, opts)?;
2425 stage_end!(stage_timer, "properties");
2426
2427 debug!("constants");
2428
2429 for c in &tables.constant {
2430 use crate::binary::signature::encoded::*;
2431 use members::Constant::*;
2432 use metadata::index::HasConstant;
2433
2434 let blob = heap_idx!(blobs, c.value);
2435
2436 let value = Some(match c.constant_type {
2437 ELEMENT_TYPE_BOOLEAN => Boolean(blob.pread_with::<u8>(0, scroll::LE)? == 1),
2438 ELEMENT_TYPE_CHAR => Char(blob.pread_with(0, scroll::LE)?),
2439 ELEMENT_TYPE_I1 => Int8(blob.pread_with(0, scroll::LE)?),
2440 ELEMENT_TYPE_U1 => UInt8(blob.pread_with(0, scroll::LE)?),
2441 ELEMENT_TYPE_I2 => Int16(blob.pread_with(0, scroll::LE)?),
2442 ELEMENT_TYPE_U2 => UInt16(blob.pread_with(0, scroll::LE)?),
2443 ELEMENT_TYPE_I4 => Int32(blob.pread_with(0, scroll::LE)?),
2444 ELEMENT_TYPE_U4 => UInt32(blob.pread_with(0, scroll::LE)?),
2445 ELEMENT_TYPE_I8 => Int64(blob.pread_with(0, scroll::LE)?),
2446 ELEMENT_TYPE_U8 => UInt64(blob.pread_with(0, scroll::LE)?),
2447 ELEMENT_TYPE_R4 => Float32(blob.pread_with(0, scroll::LE)?),
2448 ELEMENT_TYPE_R8 => Float64(blob.pread_with(0, scroll::LE)?),
2449 ELEMENT_TYPE_STRING => {
2450 let num_utf16 = blob.len() / 2;
2451 let mut offset = 0;
2452 let chars = (0..num_utf16)
2453 .map(|_| blob.gread_with(&mut offset, scroll::LE))
2454 .collect::<scroll::Result<Vec<_>>>()?;
2455 String(chars)
2456 }
2457 ELEMENT_TYPE_CLASS => {
2458 let t: u32 = blob.pread_with(0, scroll::LE)?;
2459 if t == 0 {
2460 Null
2461 } else {
2462 dll_bail!(
2463 ParseError::BadStructure("constant ELEMENT_TYPE_CLASS payload must be null reference"),
2464 );
2465 }
2466 }
2467 bad => dll_bail!(ParseError::BadElementType { tag: bad }),
2468 });
2469
2470 match c.parent {
2471 HasConstant::Field(i) => {
2472 let f_idx = i - 1;
2473
2474 match fields.get(f_idx) {
2475 Some(&i) => get_field_mut(&mut types, i).default = value,
2476 None => {
2477 dll_bail!(resolve_oob(
2478 "constant field parent",
2479 f_idx,
2480 fields.len().saturating_sub(1),
2481 ));
2482 }
2483 }
2484 }
2485 HasConstant::Param(i) => {
2486 let p_idx = i - 1;
2487
2488 match params.get(p_idx) {
2489 Some(&(parent, internal)) => {
2490 let method = get_method!(methods[parent]);
2491
2492 let param_meta = if internal == 0 {
2493 &mut method.return_type_metadata
2494 } else {
2495 &mut method.parameter_metadata[internal - 1]
2496 };
2497
2498 param_meta
2499 .as_mut()
2500 .ok_or(ResolveError::MissingRow {
2501 table: "Param",
2502 index: p_idx,
2503 })?
2504 .default = value;
2505 }
2506 None => {
2507 dll_bail!(resolve_oob(
2508 "constant parameter parent",
2509 p_idx,
2510 params.len().saturating_sub(1),
2511 ));
2512 }
2513 }
2514 }
2515 HasConstant::Property(i) => {
2516 let f_idx = i - 1;
2517
2518 match properties.get(f_idx) {
2519 Some(&(parent, internal)) => {
2520 types[parent].properties[internal].default = value;
2521 }
2522 None => {
2523 dll_bail!(resolve_oob(
2524 "constant property parent",
2525 f_idx,
2526 properties.len().saturating_sub(1),
2527 ));
2528 }
2529 }
2530 }
2531 HasConstant::Null => {
2532 dll_bail!(resolve_bad_target("constant parent cannot be null"));
2533 }
2534 }
2535 }
2536
2537 methods.sort_unstable_by_key(|m| m.parent_type);
2539
2540 let mut sem_by_event: HashMap<usize, Vec<(u16, usize)>> =
2541 HashMap::with_capacity_and_hasher(tables.event.len(), Default::default());
2542 let mut sem_by_property: HashMap<usize, Vec<(u16, usize)>> =
2543 HashMap::with_capacity_and_hasher(tables.property.len(), Default::default());
2544
2545 for s in &tables.method_semantics {
2546 use metadata::index::HasSemantics;
2547
2548 let method_idx = s.method.0 - 1;
2549 match s.association {
2550 HasSemantics::Event(e) => sem_by_event.entry(e - 1).or_default().push((s.semantics, method_idx)),
2551 HasSemantics::Property(p) => sem_by_property
2552 .entry(p - 1)
2553 .or_default()
2554 .push((s.semantics, method_idx)),
2555 HasSemantics::Null => {}
2556 }
2557 }
2558
2559 stage_start!(stage_timer);
2560 debug!("events");
2561 let events = decode_events(&mut types, &tables, &strings, &ctx, &mut sem_by_event, &mut methods)?;
2562 stage_end!(stage_timer, "events");
2563
2564 stage_start!(stage_timer);
2565 debug!("method semantics");
2566 apply_method_semantics(
2567 &mut types,
2568 &tables,
2569 &mut methods,
2570 &properties,
2571 &events,
2572 &sem_by_event,
2573 &sem_by_property,
2574 )?;
2575 stage_end!(stage_timer, "method semantics");
2576
2577 stage_start!(stage_timer);
2578 debug!("field refs / method refs");
2579 let DecodedMemberRefs {
2580 field_refs,
2581 field_map,
2582 method_refs,
2583 method_map,
2584 sig_pending_ref,
2585 } = decode_member_refs(&tables, &strings, &blobs, &module_refs, &methods, &ctx, opts)?;
2586 stage_end!(stage_timer, "field refs / method refs");
2587
2588 let m_ctx = convert::read::MethodContext {
2589 field_map: &field_map,
2590 field_indices: &fields,
2591 method_specs: &tables.method_spec,
2592 method_indices: &methods,
2593 method_map: &method_map,
2594 };
2595
2596 debug!("method impl");
2597
2598 for i in &tables.method_impl {
2599 use types::*;
2600
2601 let idx = i.class.0 - 1;
2602 match types.get_mut(idx) {
2603 Some(t) => t.overrides.push(MethodOverride {
2604 implementation: convert::read::user_method(i.method_body, &m_ctx)?,
2605 declaration: convert::read::user_method(i.method_declaration, &m_ctx)?,
2606 }),
2607 None => {
2608 dll_bail!(resolve_oob(
2609 "method override parent type",
2610 idx,
2611 types.len().saturating_sub(1),
2612 ));
2613 }
2614 }
2615 }
2616
2617 use metadata::{
2618 index::{Token, TokenTarget},
2619 table::Kind,
2620 };
2621
2622 let entry_token = dll.cli.entry_point_token.to_le_bytes().pread::<Token>(0)?;
2623
2624 let mut res = Resolution {
2625 assembly,
2626 assembly_references: assembly_refs,
2627 entry_point: if entry_token.index == 0 {
2628 None
2629 } else {
2630 let entry_idx = entry_token.index - 1;
2631 Some(match entry_token.target {
2632 TokenTarget::Table(Kind::MethodDef) => match methods.get(entry_idx) {
2633 Some(&m) => EntryPoint::Method(m),
2634 None => {
2635 dll_bail!(resolve_oob(
2636 "entry point method",
2637 entry_idx,
2638 methods.len().saturating_sub(1),
2639 ));
2640 }
2641 },
2642 TokenTarget::Table(Kind::File) => {
2643 if entry_idx < files.len() {
2644 EntryPoint::File(FileIndex(entry_idx))
2645 } else {
2646 dll_bail!(resolve_oob(
2647 "entry point file",
2648 entry_idx,
2649 files.len().saturating_sub(1),
2650 ));
2651 }
2652 }
2653 _ => dll_bail!(resolve_bad_target("entry point token must target MethodDef or File")),
2654 })
2655 },
2656 exported_types: exports,
2657 field_references: field_refs,
2658 files,
2659 manifest_resources: resources,
2660 method_references: method_refs,
2661 module,
2662 module_references: module_refs,
2663 type_definitions: types,
2664 type_references: type_refs,
2665 lazy_state: None,
2666 };
2667
2668 stage_start!(stage_timer);
2669 debug!("custom attributes");
2670
2671 if !opts.lazy_attributes {
2672 for (idx, a) in tables.custom_attribute.iter().enumerate() {
2673 use attribute::*;
2674 use members::UserMethod;
2675 use metadata::index::{CustomAttributeType, HasCustomAttribute::*};
2676
2677 let attr = Attribute {
2678 constructor: match a.attr_type {
2679 CustomAttributeType::MethodDef(i) => {
2680 let m_idx = i - 1;
2681 match methods.get(m_idx) {
2682 Some(&m) => UserMethod::Definition(m),
2683 None => {
2684 dll_bail!(resolve_oob(
2685 "custom attribute constructor method",
2686 m_idx,
2687 methods.len().saturating_sub(1),
2688 ));
2689 }
2690 }
2691 }
2692 CustomAttributeType::MemberRef(i) => {
2693 let r_idx = i - 1;
2694 match method_map.get(&r_idx) {
2695 Some(&m_idx) => UserMethod::Reference(MethodRefIndex(m_idx)),
2696 None => {
2697 dll_bail!(resolve_oob(
2698 "custom attribute constructor member reference",
2699 r_idx,
2700 method_map.len().saturating_sub(1),
2701 ));
2702 }
2703 }
2704 }
2705 CustomAttributeType::Null => {
2706 dll_bail!(resolve_bad_target("custom attribute constructor cannot be null"));
2707 }
2708 },
2709 value: optional_idx!(blobs, a.value),
2710 };
2711
2712 macro_rules! do_at_generic {
2716 ($g:expr, |$capt:ident| $do:expr) => {{
2717 use metadata::index::TypeOrMethodDef;
2718 let g = $g;
2719 match g.owner {
2720 TypeOrMethodDef::TypeDef(t) => {
2721 let $capt = &mut res.type_definitions[t - 1].generic_parameters[g.number as usize];
2722 $do;
2723 }
2724 TypeOrMethodDef::MethodDef(m) => {
2725 let $capt = &mut res[methods[m - 1]].generic_parameters[g.number as usize];
2726 $do;
2727 }
2728 TypeOrMethodDef::Null => {
2729 debug_assert!(false, "unreachable custom attribute generic owner is null");
2732 unreachable!()
2733 },
2734 }
2735 }};
2736 }
2737
2738 match a.parent {
2739 MethodDef(i) => {
2740 let m_idx = i - 1;
2741 match methods.get(m_idx) {
2742 Some(&m) => res[m].attributes.push(attr),
2743 None => {
2744 dll_bail!(resolve_oob(
2745 "custom attribute parent method",
2746 m_idx,
2747 methods.len().saturating_sub(1),
2748 ));
2749 }
2750 }
2751 }
2752 Field(i) => {
2753 let f_idx = i - 1;
2754 match fields.get(f_idx) {
2755 Some(&i) => res[i].attributes.push(attr),
2756 None => {
2757 dll_bail!(resolve_oob(
2758 "custom attribute parent field",
2759 f_idx,
2760 fields.len().saturating_sub(1),
2761 ));
2762 }
2763 }
2764 }
2765 TypeRef(i) => {
2766 let r_idx = i - 1;
2767 match res.type_references.get_mut(r_idx) {
2768 Some(r) => r.attributes.push(attr),
2769 None => {
2770 dll_bail!(resolve_oob(
2771 "custom attribute parent type reference",
2772 r_idx,
2773 res.type_references.len().saturating_sub(1),
2774 ));
2775 }
2776 }
2777 }
2778 TypeDef(i) => {
2779 let t_idx = i - 1;
2780 match res.type_definitions.get_mut(t_idx) {
2781 Some(t) => t.attributes.push(attr),
2782 None => {
2783 dll_bail!(resolve_oob(
2784 "custom attribute parent type definition",
2785 t_idx,
2786 res.type_definitions.len().saturating_sub(1),
2787 ));
2788 }
2789 }
2790 }
2791 Param(i) => {
2792 let p_idx = i - 1;
2793 match params.get(p_idx) {
2794 Some(&(parent, internal)) => {
2795 let method = &mut res[methods[parent]];
2796
2797 let param_meta = if internal == 0 {
2798 &mut method.return_type_metadata
2799 } else {
2800 &mut method.parameter_metadata[internal - 1]
2801 };
2802
2803 param_meta
2804 .as_mut()
2805 .ok_or(ResolveError::MissingRow {
2806 table: "Param",
2807 index: p_idx,
2808 })?
2809 .attributes
2810 .push(attr);
2811 }
2812 None => {
2813 dll_bail!(resolve_oob(
2814 "custom attribute parent parameter",
2815 p_idx,
2816 params.len().saturating_sub(1),
2817 ));
2818 }
2819 }
2820 }
2821 InterfaceImpl(i) => {
2822 let i_idx = i - 1;
2823
2824 match interface_idxs.get(i_idx) {
2825 Some(&(parent, internal)) => res.type_definitions[parent].implements[internal].0.push(attr),
2826 None => {
2827 dll_bail!(resolve_oob(
2828 "custom attribute parent interface implementation",
2829 i_idx,
2830 interface_idxs.len().saturating_sub(1),
2831 ));
2832 }
2833 }
2834 }
2835 MemberRef(i) => {
2836 let m_idx = i - 1;
2837
2838 match field_map.get(&m_idx) {
2839 Some(&f) => res.field_references[f].attributes.push(attr),
2840 None => match method_map.get(&m_idx) {
2841 Some(&m) => res.method_references[m].attributes.push(attr),
2842 None => {
2843 dll_bail!(resolve_oob(
2844 "custom attribute parent member reference",
2845 m_idx,
2846 tables.member_ref.len().saturating_sub(1),
2847 ));
2848 }
2849 },
2850 }
2851 }
2852 Module(_) => res.module.attributes.push(attr),
2853 DeclSecurity(i) => {
2854 use metadata::index::HasDeclSecurity;
2855
2856 let s_idx = i - 1;
2857
2858 match tables.decl_security.get(s_idx) {
2859 Some(s) => match s.parent {
2860 HasDeclSecurity::TypeDef(t) => res.type_definitions[t - 1]
2861 .security
2862 .as_mut()
2863 .ok_or(ResolveError::MissingRow {
2864 table: "DeclSecurity",
2865 index: s_idx,
2866 })?
2867 .attributes
2868 .push(attr),
2869 HasDeclSecurity::MethodDef(m) => res[methods[m - 1]]
2870 .security
2871 .as_mut()
2872 .ok_or(ResolveError::MissingRow {
2873 table: "DeclSecurity",
2874 index: s_idx,
2875 })?
2876 .attributes
2877 .push(attr),
2878 HasDeclSecurity::Assembly(_) => res
2879 .assembly
2880 .as_mut()
2881 .and_then(|a| a.security.as_mut())
2882 .ok_or(ResolveError::MissingRow {
2883 table: "DeclSecurity",
2884 index: s_idx,
2885 })?
2886 .attributes
2887 .push(attr),
2888 HasDeclSecurity::Null => {
2889 debug_assert!(false, "unreachable custom attribute DeclSecurity owner is null");
2892 unreachable!()
2893 },
2894 },
2895 None => {
2896 dll_bail!(resolve_oob(
2897 "custom attribute parent security declaration",
2898 s_idx,
2899 tables.decl_security.len().saturating_sub(1),
2900 ));
2901 }
2902 }
2903 }
2904 Property(i) => {
2905 let p_idx = i - 1;
2906
2907 match properties.get(p_idx) {
2908 Some(&(parent, internal)) => {
2909 res.type_definitions[parent].properties[internal].attributes.push(attr)
2910 }
2911 None => {
2912 dll_bail!(resolve_oob(
2913 "custom attribute parent property",
2914 p_idx,
2915 properties.len().saturating_sub(1),
2916 ));
2917 }
2918 }
2919 }
2920 Event(i) => {
2921 let e_idx = i - 1;
2922
2923 match events.get(e_idx) {
2924 Some(&(parent, internal)) => {
2925 res.type_definitions[parent].events[internal].attributes.push(attr)
2926 }
2927 None => {
2928 dll_bail!(resolve_oob(
2929 "custom attribute parent event",
2930 e_idx,
2931 events.len().saturating_sub(1),
2932 ));
2933 }
2934 }
2935 }
2936 ModuleRef(i) => {
2937 let m_idx = i - 1;
2938
2939 match res.module_references.get_mut(m_idx) {
2940 Some(m) => m.attributes.push(attr),
2941 None => {
2942 dll_bail!(resolve_oob(
2943 "custom attribute parent module reference",
2944 m_idx,
2945 res.module_references.len().saturating_sub(1),
2946 ));
2947 }
2948 }
2949 }
2950 Assembly(_) => match res.assembly.as_mut() {
2951 Some(a) => a.attributes.push(attr),
2952 None => dll_bail!(resolve_missing_row("Assembly", 0)),
2953 },
2954 AssemblyRef(i) => {
2955 let r_idx = i - 1;
2956
2957 match res.assembly_references.get_mut(r_idx) {
2958 Some(a) => a.attributes.push(attr),
2959 None => {
2960 dll_bail!(resolve_oob(
2961 "custom attribute parent assembly reference",
2962 r_idx,
2963 res.assembly_references.len().saturating_sub(1),
2964 ));
2965 }
2966 }
2967 }
2968 File(i) => {
2969 let f_idx = i - 1;
2970
2971 match res.files.get_mut(f_idx) {
2972 Some(f) => f.attributes.push(attr),
2973 None => {
2974 dll_bail!(resolve_oob(
2975 "custom attribute parent file",
2976 f_idx,
2977 res.files.len().saturating_sub(1),
2978 ));
2979 }
2980 }
2981 }
2982 ExportedType(i) => {
2983 let e_idx = i - 1;
2984
2985 match res.exported_types.get_mut(e_idx) {
2986 Some(e) => e.attributes.push(attr),
2987 None => {
2988 dll_bail!(resolve_oob(
2989 "custom attribute parent exported type",
2990 e_idx,
2991 res.exported_types.len().saturating_sub(1),
2992 ));
2993 }
2994 }
2995 }
2996 ManifestResource(i) => {
2997 let r_idx = i - 1;
2998
2999 match res.manifest_resources.get_mut(r_idx) {
3000 Some(r) => r.attributes.push(attr),
3001 None => {
3002 dll_bail!(resolve_oob(
3003 "custom attribute parent manifest resource",
3004 r_idx,
3005 res.manifest_resources.len().saturating_sub(1),
3006 ));
3007 }
3008 }
3009 }
3010 GenericParam(i) => {
3011 let g_idx = i - 1;
3012
3013 match tables.generic_param.get(g_idx) {
3014 Some(g) => do_at_generic!(g, |rg| rg.attributes.push(attr)),
3015 None => {
3016 dll_bail!(resolve_oob(
3017 "custom attribute parent generic parameter",
3018 g_idx,
3019 tables.generic_param.len().saturating_sub(1),
3020 ));
3021 }
3022 }
3023 }
3024 GenericParamConstraint(i) => {
3025 let g_idx = i - 1;
3026
3027 match constraint_map.get(&g_idx) {
3028 Some(&(generic, internal)) => do_at_generic!(tables.generic_param[generic], |g| g
3029 .type_constraints[internal]
3030 .attributes
3031 .push(attr)),
3032 None => {
3033 dll_bail!(resolve_oob(
3034 "custom attribute parent generic parameter constraint",
3035 g_idx,
3036 tables.generic_param_constraint.len().saturating_sub(1),
3037 ));
3038 }
3039 }
3040 }
3041 MethodSpec(_) => {
3042 warn!(
3043 "custom attribute {} has a MethodSpec parent, this is not supported by dotnetdll",
3044 idx
3045 );
3046 }
3047 StandAloneSig(_) => {
3048 warn!(
3049 "custom attribute {} has a StandAloneSig parent, this is not supported by dotnetdll",
3050 idx
3051 );
3052 }
3053 TypeSpec(_) => {
3054 warn!(
3055 "custom attribute {} has a TypeSpec parent, this is not supported by dotnetdll",
3056 idx
3057 );
3058 }
3059 Null => {
3060 dll_bail!(resolve_bad_target("custom attribute parent cannot be null"));
3061 }
3062 }
3063 }
3064 } stage_end!(stage_timer, "custom attributes");
3066
3067 if opts.lazy_method_bodies || opts.lazy_method_signatures || opts.lazy_property_signatures || opts.lazy_attributes {
3068 stage_start!(stage_timer);
3069 debug!("building lazy parse state");
3070
3071 let (attr_by_type, attr_by_method, attr_by_field, attr_by_assembly) = if opts.lazy_attributes {
3073 use crate::binary::metadata::index::{CustomAttributeType, HasCustomAttribute};
3074 use crate::resolved::members::UserMethod;
3075
3076 let mut by_type: HashMap<usize, Vec<lazy::AttrRaw>> = HashMap::default();
3077 let mut by_method: HashMap<usize, Vec<lazy::AttrRaw>> = HashMap::default();
3078 let mut by_field: HashMap<usize, Vec<lazy::AttrRaw>> = HashMap::default();
3079 let mut by_asm: Vec<lazy::AttrRaw> = Vec::new();
3080
3081 for a in &tables.custom_attribute {
3082 let constructor = match a.attr_type {
3083 CustomAttributeType::MethodDef(i) => UserMethod::Definition(methods[i - 1]),
3084 CustomAttributeType::MemberRef(i) => {
3085 let m_idx = match method_map.get(&(i - 1)) {
3086 Some(&m) => m,
3087 None => continue,
3088 };
3089 UserMethod::Reference(MethodRefIndex(m_idx))
3090 }
3091 CustomAttributeType::Null => continue,
3092 };
3093 let blob_idx = if a.value.is_null() { None } else { Some(a.value) };
3094 let raw = (constructor, blob_idx);
3095 match a.parent {
3096 HasCustomAttribute::TypeDef(i) => by_type.entry(i - 1).or_default().push(raw),
3097 HasCustomAttribute::MethodDef(i) => by_method.entry(i - 1).or_default().push(raw),
3098 HasCustomAttribute::Field(i) => by_field.entry(i - 1).or_default().push(raw),
3099 HasCustomAttribute::Assembly(_) => by_asm.push(raw),
3100 _ => {}
3101 }
3102 }
3103 (by_type, by_method, by_field, by_asm)
3104 } else {
3105 (HashMap::default(), HashMap::default(), HashMap::default(), Vec::new())
3106 };
3107
3108 let n = tables.method_def.len();
3109 let (pending, method_idx_to_def, body_cache) = if opts.lazy_method_bodies {
3110 debug!(" lazy method bodies");
3111 let mut pending = Vec::with_capacity(n);
3112 let mut method_idx_to_def: HashMap<MethodIndex, usize> =
3113 HashMap::with_capacity_and_hasher(n, Default::default());
3114 let mut body_cache = Vec::with_capacity(n);
3115
3116 for (def_idx, m) in tables.method_def.iter().enumerate() {
3117 if m.rva != 0 {
3118 let (bytes, offset) = dll.method_bytes(m)?;
3119 pending.push(Some(lazy::MethodPendingRaw { bytes, offset }));
3120 method_idx_to_def.insert(methods[def_idx], def_idx);
3121 } else {
3122 pending.push(None);
3123 }
3124 body_cache.push(std::sync::OnceLock::new());
3125 }
3126 (pending, method_idx_to_def, body_cache)
3127 } else {
3128 (vec![], HashMap::with_capacity_and_hasher(0, Default::default()), vec![])
3129 };
3130
3131 let (
3132 method_spec_table,
3133 field_map_for_bodies,
3134 field_indices_for_bodies,
3135 method_indices_for_bodies,
3136 method_map_for_bodies,
3137 ) = if opts.lazy_method_bodies {
3138 (
3139 tables.method_spec.clone(),
3140 field_map.clone(),
3141 fields.clone(),
3142 methods.clone(),
3143 method_map.clone(),
3144 )
3145 } else {
3146 (
3147 vec![],
3148 HashMap::with_capacity_and_hasher(0, Default::default()),
3149 vec![],
3150 vec![],
3151 HashMap::with_capacity_and_hasher(0, Default::default()),
3152 )
3153 };
3154
3155 let sig_method_indices = if opts.lazy_method_signatures && !opts.lazy_method_bodies {
3159 methods.clone()
3160 } else {
3161 vec![]
3162 };
3163
3164 let sig_property_indices = if opts.lazy_property_signatures {
3165 properties
3166 .iter()
3167 .map(|&(parent, property)| PropertyIndex {
3168 parent_type: TypeIndex(parent),
3169 property,
3170 })
3171 .collect()
3172 } else {
3173 vec![]
3174 };
3175
3176 res.lazy_state = Some(Arc::new(lazy::LazyParseState {
3177 lazy_bodies: opts.lazy_method_bodies,
3178 lazy_signatures: opts.lazy_method_signatures,
3179 lazy_property_signatures: opts.lazy_property_signatures,
3180 lazy_attributes: opts.lazy_attributes,
3181 def_len,
3182 ref_len,
3183 specs: tables.type_spec.clone(),
3184 sigs: tables.stand_alone_sig.clone(),
3185 method_spec_table,
3186 blobs,
3187 userstrings,
3188 field_map: field_map_for_bodies,
3189 field_indices: field_indices_for_bodies,
3190 method_indices: method_indices_for_bodies,
3191 method_map: method_map_for_bodies,
3192 pending,
3193 method_idx_to_def,
3194 body_cache,
3195 sig_method_indices,
3196 sig_method_idx_to_def: std::sync::OnceLock::new(),
3197 sig_pending_def,
3198 sig_cache_def: std::sync::OnceLock::new(),
3199 sig_pending_ref,
3200 sig_cache_ref: std::sync::OnceLock::new(),
3201 sig_property_indices,
3202 sig_property_idx_to_def: std::sync::OnceLock::new(),
3203 sig_pending_property,
3204 sig_cache_property: std::sync::OnceLock::new(),
3205 attr_by_type,
3206 attr_by_method,
3207 attr_by_field,
3208 attr_by_assembly,
3209 attr_method_idx_to_def: if opts.lazy_attributes {
3210 methods.iter().enumerate().map(|(i, &m)| (m, i)).collect()
3211 } else {
3212 rustc_hash::FxHashMap::default()
3213 },
3214 attr_field_idx_to_def: if opts.lazy_attributes {
3215 fields.iter().enumerate().map(|(i, &f)| (f, i)).collect()
3216 } else {
3217 rustc_hash::FxHashMap::default()
3218 },
3219 }));
3220 stage_end!(stage_timer, "lazy state construction");
3221 }
3222
3223 if !opts.lazy_method_bodies && !opts.skip_method_bodies {
3224 stage_start!(stage_timer);
3225 debug!("method bodies");
3226
3227 use rayon::prelude::*;
3228
3229 let bodies: Vec<(MethodIndex, body::Method)> = tables
3230 .method_def
3231 .par_iter()
3232 .with_min_len(MIN_PAR_LEN)
3233 .enumerate()
3234 .filter(|(_, m)| m.rva != 0)
3235 .map(|(idx, m)| -> Result<(MethodIndex, body::Method)> {
3236 let raw_body = dll.get_method(m)?;
3237 let body = lazy::decode_body_with_ctx(raw_body, &ctx, &m_ctx)?;
3238 Ok((methods[idx], body))
3239 })
3240 .collect::<Vec<Result<_>>>()
3241 .into_iter()
3242 .collect::<Result<Vec<_>>>()?;
3243
3244 for (method_idx, body) in bodies {
3245 res[method_idx].body = Some(body);
3246 }
3247 stage_end!(stage_timer, "method bodies");
3248 } debug!("resolved module {}", res.module.name);
3251
3252 Ok(res)
3253}