use strict;
use warnings;
-use Carp qw(cluck confess);
use Data::Dumper;
my $filter=0;
$Data::Dumper::Sortkeys=1;
+my $ntfs_blocksize=0x200;
-my %init;
+# $Object{"by"}="CcSomeFunction";
+# $Object{"line_enter"}=123;
+# $Object{"line_leave"}=124;
+# $Object{"process_thread"}="0x12345678/0x12345678";
+# $FileObject{$FileObject}{"FileObject"}="0x12345678";
+# $FileObject{$FileObject}{"FileSize"}="0x12345";
+# $FileObject{$FileObject}{"map"}="0x12345678" (Bcb);
+# $FileObject{$FileObject}{"pin"}{"0x1000"}="0x12345678" (Bcb);
+# $FileObject{$FileObject}{"PinAccess"}=0 or 1;
+# $Bcb{$Bcb}{"Bcb"}="0x12345678";
+# $Bcb{$Bcb}{"FileObject"}="0x12345678";
+# $Bcb{$Bcb}{"type"}="pin" or "map";
+# $Bcb{$Bcb}{"ref_count"}=1
+# $Bcb{$Bcb}{"FileOffset"}="0x1000" if {"type"} eq "pin";
+# $Bcb{$Bcb}{"Buffer"}="0x12345678"; # PAGE_SIZE-aligned for "pin", FileOffset_0-aligned for "map"
+
+my %FileObject;
my %Bcb;
END {
- print Data::Dumper->Dump([\%init,\%Bcb],[qw(%init %Bcb)]) if !$filter;
+ print Data::Dumper->Dump([\%FileObject,\%Bcb],[qw(%FileObject %Bcb)]) if !$filter;
}
+my $Object;
+
+sub tohex($)
+{
+my($num)=@_;
+
+ return sprintf("0x%X",$num);
+}
+
+sub CcInitializeCacheMap($$$$$)
+{
+my($FileObject,$AllocationSize,$FileSize,$ValidDataLength,$PinAccess)=@_;
+
+ $ValidDataLength=$FileSize if $ValidDataLength==eval("0x".("F"x8));
+ warn "FileObject $FileObject registered twice" if $FileObject{$FileObject};
+ $FileObject{$FileObject}=$Object;
+ $Object->{"FileObject"}=$FileObject;
+ $Object->{"FileSize"}=tohex($FileSize);
+ $Object->{"map"}=undef();
+ $Object->{"pin"}={};
+ $Object->{"PinAccess"}=$PinAccess;
+ CcSetFileSizes($FileObject,$AllocationSize,$FileSize,$ValidDataLength);
+}
+
+sub FObject($)
+{
+my($FileObject)=@_;
+
+ my $FObject=$FileObject{$FileObject};
+ warn "Non-existent FileObject $FileObject" if !$FObject;
+ return $FObject;
+}
+
+sub delete_FObject($)
+{
+my($FObject)=@_;
+
+ my $FileObject=$FObject->{"FileObject"};
+ do { warn "Trailing map $_ of FileObject $FileObject during its deletion" if $_; } for ($FObject->{"map"});
+ do { warn "Trailing pin $_ of FileObject $FileObject during its deletion" if $_; } for (keys(%{$FObject->{"pin"}}));
+ delete $FileObject{$FileObject};
+}
+
+sub CcUninitializeCacheMap($$)
+{
+my($FileObject,$TruncateSize)=@_;
+
+ # CcUninitializeCacheMap() w/o CcInitializeCacheMap() is allowed:
+ return if !$FileObject{$FileObject};
+ return if !(my $FObject=FObject $FileObject);
+ delete_FObject $FObject;
+}
+
+sub CcSetFileSizes($$$$)
+{
+my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)=@_;
+
+ return if !(my $FObject=FObject $FileObject);
+ # $ValidDataLength can be > $FObject->{"FileSize"};
+ warn "ValidDataLength ".tohex($ValidDataLength)." > FileSize ".tohex($FileSize)
+ if $ValidDataLength>$FileSize;
+ warn "0 != AllocationSize ".tohex($AllocationSize)." % ntfs_blocksize ".tohex($ntfs_blocksize)
+ if 0!=($AllocationSize%$ntfs_blocksize);
+ # $AllocationSize can be higher
+ warn "FileSize ".tohex($FileSize)." > AllocationSize ".tohex($AllocationSize)
+ if $FileSize>$AllocationSize;
+ $FObject->{"FileSize"}=tohex($FileSize);
+}
+
+sub BObject($)
+{
+my($Bcb)=@_;
+
+ my $BObject=$Bcb{$Bcb};
+ warn "Non-existent Bcb $Bcb" if !$BObject;
+ return $BObject;
+}
+
+sub Bcb_conflict($;@)
+{
+my($FObject,@Bcb_list)=@_;
+
+ my $arg=0;
+ my %check=(
+ "map"=>$FObject->{"map"},
+ map(("arg".($arg++)=>$_),@Bcb_list),
+ %{$FObject->{"pin"}},
+ );
+ my %reversed;
+ my $BufferBase; # relativized to FileOffset 0
+ while (my($key,$val)=each(%check)) {
+ next if !defined $val;
+ warn "Conflicting Bcb $val of keys $key and ".$reversed{$val}." of FileObject ".$FObject->{"FileObject"}
+ if $reversed{$val};
+ # Buffer base should match even between 'map's and 'pin's
+ # as the data are always mapped only once.
+ if (my $BObject=BObject $val) {
+ my $Buffer=eval $BObject->{"Buffer"};
+ $Buffer-=eval($BObject->{"FileOffset"}) if exists $BObject->{"FileOffset"};
+ warn "Non-matching Buffer base ".tohex($Buffer)." for Bcb $val"
+ if defined($BufferBase) && $Buffer!=$BufferBase;
+ $BufferBase=$Buffer;
+ }
+ $reversed{$val}=$key;
+ }
+}
+
+# New $BObject will always be forced as the last stored reference.
+sub Bcb_checkref($$)
+{
+my($BObject,$ref)=@_;
+
+ return if !(my $FObject=FObject $BObject->{"FileObject"});
+ my $type=$BObject->{"type"};
+ my $Bcb=$BObject->{"Bcb"};
+ if ($$ref) {
+ my $BObject2=$Bcb{$$ref};
+ warn "new $type Bcb $Bcb != old $type Bcb $$ref"
+ if $Bcb ne $$ref;
+ warn "new $type $Bcb type ".$BObject->{"type"}." != old $type $$ref type ".$BObject2->{"type"}
+ if $BObject->{"type"} ne $BObject2->{"type"};
+ if (!defined $BObject->{"Buffer"}) {
+ warn "HERE";
+ }
+ warn "new $type $Bcb Buffer ".$BObject->{"Buffer"}." != old $type $$ref Buffer ".$BObject2->{"Buffer"}
+ if $BObject->{"Buffer"} ne $BObject2->{"Buffer"};
+ }
+ if ($$ref && $$ref eq $Bcb) {
+ $BObject->{"ref_count"}+=$Bcb{$$ref}->{"ref_count"};
+ $$ref=undef();
+ }
+ $Bcb{$Bcb}=$BObject; # &Bcb_conflict needs this reference
+ Bcb_conflict $FObject,$Bcb;
+ $$ref=$Bcb;
+}
+
+sub map_new($;$$)
+{
+my($FileObject,$FileOffset,$Length)=@_;
+
+ return if !(my $FObject=FObject $FileObject);
+ if (defined($FileOffset) && defined($Length)) {
+ warn "Mapping data (end ".tohex($FileOffset+$Length).") out of FileSize ".$FObject->{"FileSize"}
+ if $FileOffset+$Length>eval($FObject->{"FileSize"});
+ }
+ $Object->{"FileObject"}=$FileObject;
+ if (defined $FileOffset) {
+ $Object->{"FileOffset"}=tohex($FileOffset);
+ }
+ $Object->{"type"}="map";
+ $Object->{"ref_count"}=1;
+}
+
+sub map_new_leave($;$)
+{
+my($Bcb,$Buffer)=@_;
+
+ $Object->{"Bcb"}=$Bcb;
+ return if !(my $FObject=FObject $Object->{"FileObject"});
+
+ if (defined $Buffer) {
+ $Object->{"Buffer"}=tohex(eval($Buffer)-(eval($Object->{"FileOffset"}) || 0));
+ }
+ delete $Object->{"FileOffset"};
+
+ my $ref=\$FObject->{"map"};
+ Bcb_checkref $Object,$ref;
+}
+
+sub CcMapData($$$)
+{
+my($FileObject,$FileOffset,$Length)=@_;
+
+ map_new $FileObject,$FileOffset,$Length;
+}
+
+sub CcMapData_leave($$)
+{
+my($Bcb,$Buffer)=@_;
+
+ map_new_leave $Bcb,$Buffer;
+}
+
+sub pin_new($$$)
+{
+my($FileObject,$FileOffset,$Length)=@_;
+
+ return if !(my $FObject=FObject $FileObject);
+ warn "Pinning of non-PinAccess FileObject $FileObject" if !$FObject->{"PinAccess"};
+ warn "Mapping data (end ".tohex($FileOffset+$Length).") out of FileSize ".$FObject->{"FileSize"}
+ if $FileOffset+$Length>eval($FObject->{"FileSize"});
+ warn "Pinning Length ".tohex($Length)." > 0x1000" if $Length>0x1000;
+ warn "Pinning across file page (start=".tohex($FileOffset).",end-1=".tohex($FileOffset+$Length-1).")"
+ if ($FileOffset&~0xFFF)!=(($FileOffset+$Length-1)&~0xFFF);
+ $Object->{"FileObject"}=$FileObject;
+ $Object->{"FileOffset"}=tohex($FileOffset);
+ $Object->{"type"}="pin";
+ $Object->{"ref_count"}=1;
+}
+
+sub pin_new_leave($$)
+{
+my($Bcb,$Buffer)=@_;
+
+ $Object->{"Bcb"}=$Bcb;
+ return if !(my $FObject=FObject $Object->{"FileObject"});
+ $Object->{"Buffer"}=tohex(eval($Buffer)-(eval($Object->{"FileOffset"})&0xFFF));
+ my $shift=eval($Object->{"FileOffset"})&0xFFF;
+ $Object->{"FileOffset"}=tohex(eval($Object->{"FileOffset"})-$shift);
+ $Object->{"Buffer"}=tohex(eval($Buffer)-$shift);
+
+ my $ref=\$FObject->{"pin"}{$Object->{"FileOffset"}};
+ Bcb_checkref $Object,$ref;
+}
+
+sub CcPinRead($$$)
+{
+my($FileObject,$FileOffset,$Length)=@_;
+
+ pin_new $FileObject,$FileOffset,$Length;
+}
+
+sub CcPinRead_leave($$)
+{
+my($Bcb,$Buffer)=@_;
+
+ pin_new_leave $Bcb,$Buffer;
+}
+
+sub CcPreparePinWrite($$$)
+{
+my($FileObject,$FileOffset,$Length)=@_;
+
+ pin_new $FileObject,$FileOffset,$Length;
+}
+
+sub CcPreparePinWrite_leave($$)
+{
+my($Bcb,$Buffer)=@_;
+
+ pin_new_leave $Bcb,$Buffer;
+}
+
+sub CcPinMappedData($$$)
+{
+my($FileObject,$FileOffset,$Length)=@_;
+
+ pin_new $FileObject,$FileOffset,$Length;
+}
+
+sub CcPinMappedData_leave($)
+{
+my($Bcb)=@_;
+
+ return if !(my $FObject=FObject $Object->{"FileObject"});
+ do { warn "CcPinMappedData() with Bcb $Bcb on non-CcMapData()ed FileObject ".$Object->{"FileObject"}; return; }
+ if !(my $mapBcb=$FObject->{"map"});
+ return if !(my $BmapObject=BObject $mapBcb);
+ my $Buffer=tohex(eval($BmapObject->{"Buffer"})+eval($Object->{"FileOffset"}));
+ pin_new_leave $Bcb,$Buffer;
+}
+
+sub CcRemapBcb($)
+{
+my($Bcb)=@_;
+
+ return if !(my $BObject=BObject $Bcb);
+ map_new $BObject->{"FileObject"};
+ $Object->{"Buffer"}=tohex(eval($BObject->{"Buffer"})-eval($BObject->{"FileOffset"} || 0));
+}
+
+sub CcRemapBcb_leave($)
+{
+my($r)=@_;
+
+ map_new_leave $r;
+}
+
+sub unpin($)
+{
+my($Bcb)=@_;
+
+ return if !(my $BObject=BObject $Bcb);
+ return if --$BObject->{"ref_count"};
+ return if !(my $FObject=FObject $BObject->{"FileObject"});
+ for my $ref ($BObject->{"type"} eq "map" ? \$FObject->{"map"} : \$FObject->{"pin"}{$BObject->{"FileOffset"}}) {
+ warn "Final unpin but ".$BObject->{"type"}." Bcb $Bcb not registered"
+ ." in FileObject ".$FObject->{"FileObject"}." ref ".($$ref || "<undef>")
+ if !$$ref || $$ref ne $Bcb;
+ if ($$ref && $$ref eq $Bcb) {
+ $$ref=undef();
+ delete $FObject->{"pin"}{$BObject->{"FileOffset"}} if $BObject->{"type"} eq "pin";
+ }
+ }
+ delete $Bcb{$Bcb};
+}
+
+sub CcUnpinData($)
+{
+my($Bcb)=@_;
+
+ unpin $Bcb;
+}
+
+sub CcUnpinDataForThread($)
+{
+my($Bcb)=@_;
+
+ unpin $Bcb;
+}
+
+sub IRP_MJ_CLOSE($)
+{
+my($FileObject)=@_;
+
+ return if !$FileObject{$FileObject};
+ return if !(my $FObject=FObject $FileObject);
+ warn "CcUnpinData() not called for FileObject $FileObject before IRP_MJ_CLOSE";
+ delete_FObject $FObject;
+}
+
+
local $_;
my $hex='0x[\dA-F]+';
-my(@lastmap_CcMapData,@lastmap_CcPinRead,@lastmap_CcPreparePinWrite,@lastmap_CcPinMappedData,@lastmap_CcRemapBcb);
-my $last_irp_mj;
+my %last_irp_mj;
+my %enter_leave;
while (<>) {
chomp;
- s#^ *TraceFS[(]($hex)/($hex)[)]: ## or do { print "$_\n" if $filter; next; };
- my($process,$thread)=($1,$2);
+ s/\r$//;
+ s#^ *TraceFS[(]($hex/$hex)[)]: ## or do { print "$_\n" if $filter; next; };
+ my($process_thread)=($1);
- if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)=
+ $Object=undef();
+ if (/^enter: (\w+)/) {
+ $Object={};
+ $Object->{"by"}=$1;
+ $Object->{"line_enter"}=$.;
+ $Object->{"process_thread"}=$process_thread;
+ push @{$enter_leave{$process_thread}},$Object;
+ }
+ if (/^leave: (\w+)/) {
+ warn "Empty pop stack during 'leave' of $1" if !($Object=pop @{$enter_leave{$process_thread}});
+ warn "Non-matching popped 'by' ".$Object->{"by"}." ne current 'leave' $1"
+ if $Object->{"by"} ne $1;
+ $Object->{"line_leave"}=$.;
+ }
+
+ if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength,$PinAccess)=
/^enter: CcInitializeCacheMap: FileObject=($hex),FileSizes,->AllocationSize=($hex),->FileSize=($hex),->ValidDataLength=($hex),PinAccess=([01]),/) {
- $AllocationSize=eval($AllocationSize);
- $FileSize=eval($FileSize);
- 0==($AllocationSize%0x200) or die;
- int($AllocationSize/0x200)==int(($FileSize+0x1FF)/0x200) or die;
- $ValidDataLength eq "0x".("F"x8) or eval($ValidDataLength)==$FileSize or die;
- !exists $init{$FileObject} or die;
- $init{$FileObject}={
- "FileObject"=>$FileObject,
- "size"=>$FileSize,
- "unmaps"=>0,
- "maps"=>[],
- "line"=>$.,
- "Bcb_map"=>undef(),
- "Bcb_pin"=>{},
- };
+ CcInitializeCacheMap $FileObject,eval($AllocationSize),eval($FileSize),eval($ValidDataLength),eval($PinAccess);
next;
}
if (my($FileObject,$TruncateSize)=
/^enter: CcUninitializeCacheMap: FileObject=($hex),TruncateSize=($hex),/) {
- $TruncateSize=eval($TruncateSize);
- next if !exists $init{$FileObject};
- $init{$FileObject}->{"unmaps"}==@{$init{$FileObject}->{"maps"}} or die;
- delete $init{$FileObject};
+ CcUninitializeCacheMap $FileObject,eval($TruncateSize);
+ next;
+ }
+
+ if (my($FileObject,$AllocationSize,$FileSize,$ValidDataLength)=
+ /^enter: CcSetFileSizes: FileObject=($hex),FileSizes,->AllocationSize=($hex),->FileSize=($hex),->ValidDataLength=($hex)/) {
+ CcSetFileSizes $FileObject,eval($AllocationSize),eval($FileSize),eval($ValidDataLength);
next;
}
if (my($FileObject,$FileOffset,$Length)=
/^enter: CcMapData: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) {
- $FileOffset=eval $FileOffset;
- $Length=eval $Length;
- die if !(my $reg=$init{$FileObject});
- die if $FileOffset+$Length>$reg->{"size"};
- my $newmap={
- "FileOffset"=>$FileOffset,
- "Length"=>$Length,
- "init"=>$reg,
- "line"=>$.,
- "by"=>"CcMapData",
- };
- push @{$reg->{"maps"}},$newmap;
- push @lastmap_CcMapData,$newmap;
+ CcMapData $FileObject,eval($FileOffset),eval($Length);
next;
}
if (my($Bcb,$Buffer)=
/^leave: CcMapData: r=1,Bcb=($hex),Buffer=($hex)/) {
- die if !(my $lastmap=pop @lastmap_CcMapData);
- $lastmap->{"Bcb"}=$Bcb;
- $lastmap->{"Buffer"}=$Buffer;
- $lastmap->{"process"}=$process;
- $lastmap->{"thread"}=$thread;
- $Bcb{$Bcb}=$lastmap->{"init"};
- die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} ne $Bcb;
- $lastmap->{"init"}->{"Bcb_map"}=$Bcb;
- for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) {
- die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb;
- }
+ CcMapData_leave $Bcb,$Buffer;
next;
}
if (my($FileObject,$FileOffset,$Length)=
/^enter: CcPinRead: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) {
- $FileOffset=eval $FileOffset;
- $Length=eval $Length;
- die if !(my $reg=$init{$FileObject});
- die if $FileOffset+$Length>$reg->{"size"};
- my $newmap={
- "FileOffset"=>$FileOffset,
- "Length"=>$Length,
- "init"=>$reg,
- "line"=>$.,
- "by"=>"CcPinRead",
- };
- push @{$reg->{"maps"}},$newmap;
- push @lastmap_CcPinRead,$newmap;
+ CcPinRead $FileObject,eval($FileOffset),eval($Length);
next;
}
if (my($Bcb,$Buffer)=
/^leave: CcPinRead: r=1,Bcb=($hex),Buffer=($hex)/) {
- die if !(my $lastmap=pop @lastmap_CcPinRead);
- $lastmap->{"Bcb"}=$Bcb;
- $lastmap->{"Buffer"}=$Buffer;
- $lastmap->{"process"}=$process;
- $lastmap->{"thread"}=$thread;
- $Bcb{$Bcb}=$lastmap->{"init"};
- my $myoffs=$lastmap->{"FileOffset"}&~0xFFF;
- die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb;
- for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) {
- next if $pinoffs==$myoffs;
- die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb;
- }
- $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb;
- die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb;
+ CcPinRead_leave $Bcb,$Buffer;
next;
}
if (my($FileObject,$FileOffset,$Length)=
/^enter: CcPreparePinWrite: FileObject=($hex),FileOffset=($hex),Length=($hex),Zero=([01]),Flags=0x1/) {
- $FileOffset=eval $FileOffset;
- $Length=eval $Length;
- die if !(my $reg=$init{$FileObject});
- die if $FileOffset+$Length>$reg->{"size"};
- my $newmap={
- "FileOffset"=>$FileOffset,
- "Length"=>$Length,
- "init"=>$reg,
- "line"=>$.,
- "by"=>"CcPreparePinWrite",
- };
- push @{$reg->{"maps"}},$newmap;
- push @lastmap_CcPreparePinWrite,$newmap;
+ CcPreparePinWrite $FileObject,eval($FileOffset),eval($Length);
next;
}
if (my($Bcb,$Buffer)=
/^leave: CcPreparePinWrite: r=1,Bcb=($hex),Buffer=($hex)/) {
- die if !(my $lastmap=pop @lastmap_CcPreparePinWrite);
- $lastmap->{"Bcb"}=$Bcb;
- $lastmap->{"Buffer"}=$Buffer;
- $lastmap->{"process"}=$process;
- $lastmap->{"thread"}=$thread;
- $Bcb{$Bcb}=$lastmap->{"init"};
- my $myoffs=$lastmap->{"FileOffset"}&~0xFFF;
- die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb;
- for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) {
- next if $pinoffs==$myoffs;
- die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb;
- }
- $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb;
- die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb;
+ CcPreparePinWrite_leave $Bcb,$Buffer;
next;
}
if (my($FileObject,$FileOffset,$Length)=
/^enter: CcPinMappedData: FileObject=($hex),FileOffset=($hex),Length=($hex),Flags=0x1/) {
- $FileOffset=eval $FileOffset;
- $Length=eval $Length;
- die if !(my $reg=$init{$FileObject});
- die if $FileOffset+$Length>$reg->{"size"};
- my $newmap={
- "FileOffset"=>$FileOffset,
- "Length"=>$Length,
- "init"=>$reg,
- "line"=>$.,
- "by"=>"CcPinMappedData",
- };
- push @{$reg->{"maps"}},$newmap;
- push @lastmap_CcPinMappedData,$newmap;
+ CcPinMappedData $FileObject,eval($FileOffset),eval($Length);
next;
}
- if (my($Bcb,$Buffer)=
+ if (my($Bcb)=
/^leave: CcPinMappedData: r=1,Bcb=($hex)/) {
- die if !(my $lastmap=pop @lastmap_CcPinMappedData);
- $lastmap->{"Bcb"}=$Bcb;
- $lastmap->{"process"}=$process;
- $lastmap->{"thread"}=$thread;
- $Bcb{$Bcb}=$lastmap->{"init"};
- my $myoffs=$lastmap->{"FileOffset"}&~0xFFF;
- die if defined $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} && $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs} ne $Bcb;
- for my $pinoffs (keys(%{$lastmap->{"init"}->{"Bcb_pin"}})) {
- next if $pinoffs==$myoffs;
- die $pinoffs if $lastmap->{"init"}->{"Bcb_pin"}->{$pinoffs} eq $Bcb;
- }
- $lastmap->{"init"}->{"Bcb_pin"}->{$myoffs}=$Bcb;
- die if $lastmap->{"init"}->{"Bcb_map"} && $lastmap->{"init"}->{"Bcb_map"} eq $Bcb;
+ CcPinMappedData_leave $Bcb;
next;
}
if (my($Bcb)=
/^enter: CcRemapBcb: Bcb=($hex)/) {
- die if !(my $reg=$Bcb{$Bcb});
- my $newmap={
- "remap"=>1,
- "Bcb"=>$Bcb,
- "init"=>$reg,
- "line"=>$.,
- "by"=>"CcRemapBcb of $Bcb",
- };
- push @{$reg->{"maps"}},$newmap;
- push @lastmap_CcRemapBcb,$newmap;
+ CcRemapBcb $Bcb;
+ next;
}
if (my($r)=
/^leave: CcRemapBcb: r=($hex)/) {
- die if !(my $lastmap=pop @lastmap_CcRemapBcb);
- $lastmap->{"process"}=$process;
- $lastmap->{"thread"}=$thread;
- die "CcRemapBcb enterBcb ".$lastmap->{"Bcb"}." != leaveBcb ".$r
- if $lastmap->{"Bcb"} ne $r;
+ CcRemapBcb_leave $r;
next;
}
if (my($Bcb)=
- /^enter: CcUnpinData(?:|ForThread): Bcb=($hex)/) {
- die if !(my $regbcb=$Bcb{$Bcb});
- $regbcb->{"unmaps"}++;
- die if $regbcb->{"unmaps"}>@{$regbcb->{"maps"}};
- if ($regbcb->{"unmaps"}==@{$regbcb->{"maps"}}) {
- warn "Full CcUnPinData for FileObject ".$regbcb->{"FileObject"};
-# $regbcb->{"unmaps"}=0;
-# $regbcb->{"maps"}=[];
- $regbcb->{"unmaps"}++;
- push @{$regbcb->{"maps"}},{
- "unpinned"=>"=========================================",
- "line"=>$.,
- };
- }
- $regbcb->{"Bcb_map"}=undef() if $regbcb->{"Bcb_map"} && $regbcb->{"Bcb_map"} eq $Bcb;
- for my $pinoffs (keys(%{$regbcb->{"Bcb_pin"}})) {
- delete $regbcb->{"Bcb_pin"}->{$pinoffs} if $regbcb->{"Bcb_pin"}->{$pinoffs} eq $Bcb;
- }
+ /^enter: CcUnpinData: Bcb=($hex)/) {
+ CcUnpinData $Bcb;
+ next;
+ }
+ if (my($Bcb)=
+ /^enter: CcUnpinDataForThread: Bcb=($hex)/) {
+ CcUnpinDataForThread $Bcb;
next;
}
if (my($irp_mj)=
- /^enter: (IRP_MJ_.*)/) {
- $last_irp_mj=$irp_mj;
+ /^enter: (IRP_MJ_\w+)/) {
+ push @{$last_irp_mj{$process_thread}},$irp_mj;
+ next;
+ }
+ if (my($irp_mj)=
+ /^leave: (IRP_MJ_\w+)/) {
+ my $irp_mj_last=pop @{$last_irp_mj{$process_thread}};
+ warn "Non-matching popped IRP name irp_mj $irp_mj ne irp_mj_last $irp_mj_last"
+ if $irp_mj ne $irp_mj_last;
next;
}
if (my($FileObject)=
- /^debug_irp: IoStackLocation->FileObject=($hex):/) {
- next if $last_irp_mj ne "IRP_MJ_CLOSE";
- warn "IRP_MJ_CLOSE: still mapped $FileObject" if $init{$FileObject}->{"unmaps"}!=@{$init{$FileObject}->{"maps"}};
- delete $init{$FileObject};
+ /^FileObject=($hex):/) {
+ my $aref=$last_irp_mj{$process_thread};
+ my $irp_mj_last=${$aref}[$#$aref];
+ next if $irp_mj_last ne "IRP_MJ_CLOSE";
+ IRP_MJ_CLOSE $FileObject;
next;
}
print "$_\n" if $filter;
}
-for my $key (keys(%init)) {
- warn "EXIT: still mapped $key" if $init{$key}->{"unmaps"}!=@{$init{$key}->{"maps"}};
+for my $FileObject (keys(%FileObject)) {
+ warn "EXIT: still CcInitializeCacheMap FileObject $FileObject";
+ next if !(my $FObject=FObject $FileObject);
+ delete_FObject $FObject;
}