|
DataMuseum.dkPresents historical artifacts from the history of: Rational R1000/400 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Rational R1000/400 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - download
Length: 48128 (0xbc00) Types: Ada Source Notes: 03_class, FILE, R1k_Segment, e3_tag, package body Size_Utilities, seg_00462f
└─⟦8527c1e9b⟧ Bits:30000544 8mm tape, Rational 1000, Arrival backup of disks in PAM's R1000 └─ ⟦5a81ac88f⟧ »Space Info Vol 1« └─⟦this⟧
with Io; with Lrm_Utilities; with Sizing_Parameters; use Sizing_Parameters; with String_Utilities; with Representation_Clauses; with Names_And_Expressions; with Bounds_Utilities; with Declarations; with Ada_Program; with Type_Information; with Lrm_Renames; use Lrm_Renames; package body Size_Utilities is function Static_Value (Expression : Ada_Program.Expression) return Long_Integer renames Lrm_Utilities.Static_Value; function Static_Value (Expression : Ada_Program.Expression) return Float renames Lrm_Utilities.Static_Value; function "=" (Left, Right : Types.Type_Definition_Kinds) return Boolean renames Types."="; function "=" (Left, Right : Ada.Element) return Boolean renames Ada."="; procedure Size (Ref_Id : Ada_Program.Identifier_Reference := Ada_Program.Nil_Element; Ignore_Rep_Clauses : Boolean; Original : Type_Information.Type_Definition; Constraint : Type_Information.Type_Constraint; Result : out Long_Natural; Requires_Alignment : in out Boolean; Static : in out Boolean); procedure Size (For_Type : Type_Information.Type_Definition; Ignore_Rep_Clauses : Boolean; Result : out Long_Natural; Requires_Alignment : in out Boolean; Static : in out Boolean); function Round_Up_To_Alignment (Exact_Size : Long_Natural; Alignment : Long_Natural) return Long_Natural is begin if Exact_Size mod Alignment = 0 then return Exact_Size; else return ((Exact_Size / Alignment) + 1) * Alignment; end if; end Round_Up_To_Alignment; procedure Expression_Value (Of_Expression : Ada.Element; Result : out Long_Natural; Static : out Boolean) is begin Result := Static_Value (Of_Expression); Static := True; exception when Lrm_Utilities.Not_Static => Result := 0; Static := False; end Expression_Value; procedure Access_Size (Of_Access : Types.Type_Definition; Result : out Long_Natural; Static : in out Boolean) is Storage_Size : Names_And_Expressions.Expression; begin -- Storage_Size := Rep_Specs.Associated_Storage_Size (Of_Access); -- could be used to compute the collection size Result := Access_Type_Size; Static := True; end Access_Size; function Size_Of_Dimension (Lower_Bound, Upper_Bound : Long_Integer) return Long_Natural is Size : Long_Natural; begin Size := Upper_Bound - Lower_Bound + 1; return Size; exception when Constraint_Error => return 0; when Numeric_Error => return 0; end Size_Of_Dimension; procedure Record_Rep_Spec_Size (Rep_Spec : Ada.Element; Result : out Long_Natural; Static : in out Boolean) is Components : Ada.Element_Iterator; Component : Ada.Element; Current_Offset : Long_Natural := 0; Current_Size, Max_Size : Long_Natural := 0; Ubound, Lbound : Long_Integer := 0; Non_Static_Lbound, Non_Static_Ubound : Ada.Element; begin Components := Rep_Specs.Clause_Components (Rep_Spec); while not Ada.Done (Components) loop -- iterate through component -- rep specs Component := Ada.Value (Components); if Rep_Specs.Valid_Component (Component) then Expression_Value (Rep_Specs.Component_Offset (Component), Current_Offset, Static); Bounds_Utilities.Find_Range (Rep_Specs.Component_Range (Component), Lbound, Ubound, Static, Non_Static_Lbound, Non_Static_Ubound); Current_Size := Current_Offset * Bytes + Ubound + 1; if Current_Size > Max_Size then -- multiple offsets with -- different ranges Max_Size := Current_Size; end if; end if; Ada.Next (Components); end loop; Result := Max_Size; end Record_Rep_Spec_Size; function Get_Referenced_Enum_Literal (Constraint : Ada.Element) return Ada.Element is begin case Names_And_Expressions.Kind (Constraint) is when Names_And_Expressions.An_Enumeration_Literal => return Ada.Definition (Constraint); when others => return Ada.Nil_Element; end case; end Get_Referenced_Enum_Literal; function Choice_Matches_Constraint (Choices : Ada.Element_Iterator; Constraint : Ada.Element) return Boolean is Local_Choices : Ada.Element_Iterator := Choices; Choice : Ada.Element; begin if Ada.Is_Nil (Constraint) then return False; end if; while not Ada.Done (Local_Choices) loop Choice := Ada.Value (Local_Choices); case Type_Information.Choice_Kind (Choice) is when Type_Information.A_Simple_Expression => null; when Type_Information.A_Discrete_Range => null; when Type_Information.Others_Choice => null; -- return True; could be if all others implemented when Type_Information.An_Identifier_Reference => return Ada.Definition (Choice) = Get_Referenced_Enum_Literal (Constraint); when Type_Information.Not_A_Choice => return False; end case; Ada.Next (Local_Choices); end loop; return False; end Choice_Matches_Constraint; procedure Component_List_Size (Components : in out Ada.Element_Iterator; Ignore_Rep_Clauses : Boolean; With_Constraints : Type_Information.Type_Constraint; Result : out Long_Natural; Requires_Alignment : in out Boolean; Static : in out Boolean) is -- compute the total size of all components Component, Component_Type : Ada.Element; Current_Size, Temp_Size, Accume_Size : Long_Natural := 0; Inner_Components, Variant_Items : Ada.Element_Iterator; Component_Requires_Alignment : Boolean; Variant_Component_Requires_Alignment : Boolean; Variant : Ada.Element; Variant_Choices : Ada.Element_Iterator; Number_Of_Id_Decls : Long_Natural := 1; begin Requires_Alignment := False; while not Ada.Done (Components) loop Component := Ada.Value (Components); Current_Size := 0; case Types.Component_Kind (Component) is when Types.A_Variable_Component => Number_Of_Ids (Component, Number_Of_Id_Decls); Component_Type := Declarations.Object_Type (Component); Size (Component_Type, Ignore_Rep_Clauses, Current_Size, Component_Requires_Alignment, Static); when Types.A_Variant_Part_Component => -- compute the size of the largest variant -- unless constraint selects a variant Variant_Items := Types.Variant_Item_List (Component); while not Ada.Done (Variant_Items) loop Variant := Ada.Value (Variant_Items); Variant_Choices := Type_Information.Variant_Choices (Variant); Inner_Components := Types.Inner_Record_Components (Variant); Component_List_Size (Inner_Components, Ignore_Rep_Clauses, With_Constraints, Temp_Size, Variant_Component_Requires_Alignment, Static); if Static then if Choice_Matches_Constraint (Variant_Choices, With_Constraints) then Current_Size := Temp_Size; Component_Requires_Alignment := Variant_Component_Requires_Alignment; exit; -- this variant is selected by the -- constraint elsif Temp_Size > Current_Size then Current_Size := Temp_Size; Component_Requires_Alignment := Variant_Component_Requires_Alignment; end if; else Result := 0; return; end if; Ada.Next (Variant_Items); end loop; when Types.A_Null_Component => Current_Size := 0; Static := True; when Types.Not_A_Component => Result := 0; Static := False; return; end case; if Static then if Component_Requires_Alignment then Requires_Alignment := True; Accume_Size := Current_Size + Number_Of_Id_Decls * Round_Up_To_Alignment (Accume_Size, Record_Component_Alignment); else Accume_Size := Accume_Size + (Number_Of_Id_Decls * Current_Size); end if; else Result := 0; return; end if; Ada.Next (Components); end loop; Result := Accume_Size; end Component_List_Size; function Has_Default_Values (Discriminants : Ada.Element_Iterator) return Boolean is Local : Ada.Element_Iterator := Discriminants; Discriminant : Ada.Element; begin while not Ada.Done (Local) loop Discriminant := Ada.Value (Local); if Lrm_Utilities.Is_Initialized (Discriminant) then return True; end if; Ada.Next (Local); end loop; return False; end Has_Default_Values; procedure Record_Size (Of_Record : Type_Information.Type_Definition; Ignore_Rep_Clauses : Boolean; With_Constraints : Type_Information.Type_Constraint; Result : out Long_Natural; Requires_Alignment : in out Boolean; Static : in out Boolean) is Record_Components : Ada.Element_Iterator; Rep_Spec : Ada.Element; begin Rep_Spec := Rep_Specs.Associated_Record_Representation (Of_Record); if Ignore_Rep_Clauses or else Ada.Is_Nil (Rep_Spec) then Record_Components := Types.Record_Components (Of_Record); if Type_Information.Is_Discriminated (Of_Record) and then Has_Default_Values (Type_Information.Discriminants (Of_Record)) then Component_List_Size (Components => Record_Components, Ignore_Rep_Clauses => Ignore_Rep_Clauses, With_Constraints => Ada.Nil_Element, Result => Result, Requires_Alignment => Requires_Alignment, Static => Static); else Component_List_Size (Components => Record_Components, Ignore_Rep_Clauses => Ignore_Rep_Clauses, With_Constraints => With_Constraints, Result => Result, Requires_Alignment => Requires_Alignment, Static => Static); end if; else Record_Rep_Spec_Size (Rep_Spec, Result, Static); Requires_Alignment := False; end if; end Record_Size; procedure Number_Of_Elements (Index_Constraints : Ada_Program.Element_Iterator; Count : out Long_Natural; Static : in out Boolean) is Indices : Ada.Element_Iterator := Index_Constraints; Index_Constraint : Types.Subtype_Indication; Lower_Expression, Upper_Expression : Types.Expression; Lower, Upper : Long_Integer; Total_Elements : Long_Natural := 1; begin Static := True; while not Ada.Done (Indices) loop Index_Constraint := Ada.Value (Indices); Bounds_Utilities.Find_Range (Index_Constraint, Lower, Upper, Static, Lower_Expression, Upper_Expression); exit when not Static; Total_Elements := Total_Elements * Size_Of_Dimension (Lower, Upper); Ada.Next (Indices); end loop; Count := Total_Elements; end Number_Of_Elements; function Is_Character (Type_Def : Types.Type_Definition) return Boolean is Last : Ada.Element := Types.Last_Constraint (Type_Def); begin return String_Utilities.Equal (Ada.Image (Last), "CHARACTER") or else String_Utilities.Equal (Declarations.Name (Ada.Parent (Last)), "CHARACTER"); end Is_Character; function Is_Boolean (Type_Def : Types.Type_Definition) return Boolean is Last : Ada.Element := Types.Last_Constraint (Type_Def); begin return String_Utilities.Equal (Ada.Image (Last), "BOOLEAN") or else String_Utilities.Equal (Declarations.Name (Ada.Parent (Last)), "BOOLEAN"); end Is_Boolean; procedure Array_Size (Of_Array : Type_Information.Type_Definition; Ignore_Rep_Clauses : Boolean; Index_Constraints : Ada_Program.Element_Iterator; Result : out Long_Natural; Static : in out Boolean) is Array_Elements : Long_Natural; Array_Component_Type : Types.Type_Definition; Component_Size : Long_Natural; Requires_Alignment : Boolean := False; begin Result := 0; Array_Component_Type := Types.Component_Type (Of_Array); if Is_Character (Array_Component_Type) then -- string type Component_Size := Character_Size; elsif Is_Boolean (Array_Component_Type) then -- bit string Component_Size := Boolean_Size; else Size (For_Type => Array_Component_Type, Ignore_Rep_Clauses => Ignore_Rep_Clauses, Result => Component_Size, Requires_Alignment => Requires_Alignment, Static => Static); Component_Size := Round_Up_To_Alignment (Component_Size, Array_Component_Alignment); end if; if Static then Number_Of_Elements (Index_Constraints, Array_Elements, Static); if Static then if Requires_Alignment then Result := Array_Elements * Round_Up_To_Alignment (Component_Size, Record_Component_Alignment); else Result := Array_Elements * Component_Size; end if; end if; end if; end Array_Size; procedure Find_Fixed_Constraints (Ref_Id : Ada.Identifier_Reference := Ada.Nil_Element; Root : Types.Type_Definition; First : Types.Type_Constraint; Range_Constraint : out Types.Type_Constraint; Delta_Constraint : out Types.Type_Constraint) is Got_Range, Got_Delta : Boolean := False; Element : Ada.Element; procedure Process_Constraint (Current : Types.Type_Constraint) is begin case Types.Constraint_Kind (Current) is when Types.A_Simple_Range | Types.A_Range_Attribute => if not Got_Range then Range_Constraint := Current; Got_Range := True; end if; when Types.A_Fixed_Point_Constraint => if not Got_Delta then Delta_Constraint := Current; Got_Delta := True; end if; if not Got_Range and then not Ada.Is_Nil (Types.Fixed_Point_Constraint (Current)) then Range_Constraint := Types.Fixed_Point_Constraint (Current); Got_Range := True; end if; when others => null; end case; end Process_Constraint; begin Range_Constraint := Ada.Nil_Element; Delta_Constraint := Ada.Nil_Element; Element := Ref_Id; Process_Constraint (First); while not Got_Range or else not Got_Delta loop if Ada.Is_Nil (Element) then Process_Constraint (Types.Ground_Type (Root)); exit; end if; Element := Ada.Definition (Element); exit when Ada.Is_Nil (Element); -- For Generic Formal types. Element := Types.Last_Constraint (Decls.Type_Specification (Element)); case Types.Kind (Element) is when Types.A_Subtype_Indication => Process_Constraint (Types.Constraint (Element)); when Types.A_Fixed_Type_Definition => Process_Constraint (Element); when others => exit; -- shouldn't happen end case; end loop; end Find_Fixed_Constraints; procedure Size (For_Type : Type_Information.Type_Definition; Ignore_Rep_Clauses : Boolean; Result : out Long_Natural; Requires_Alignment : in out Boolean; Static : in out Boolean) is Element : Ada.Element := Types.Last_Constraint (For_Type); Size_Expression : Ada_Program.Element; Ubound, Lbound : Long_Integer; U_Bound, L_Bound : Float; Digits_Accuracy : Long_Natural; Constraint, Range_Constraint, Delta_Constraint : Types.Type_Constraint; Is_Packed : Boolean; begin Result := 0; Requires_Alignment := False; loop if Ada.Is_Nil (Element) then Static := False; return; end if; Size_Expression := Rep_Specs.Associated_Size (Element); if Ignore_Rep_Clauses or else Ada.Is_Nil (Size_Expression) then case Types.Kind (Element) is when Types.A_Subtype_Indication => Constraint := Types.Constraint (Element); if Ada.Is_Nil (Constraint) then -- Can't happen, LAST_CONSTRAINT returns -- a constrained subtype or a base type ... Static := False; exit; end if; Size (Ref_Id => Types.Type_Mark (Element), Ignore_Rep_Clauses => Ignore_Rep_Clauses, Original => Element, Constraint => Constraint, Result => Result, Requires_Alignment => Requires_Alignment, Static => Static); exit; when Types.An_Enumeration_Type_Definition => if Is_Character (Element) then Result := Character_Size; Static := True; elsif Is_Boolean (Element) then Result := Boolean_Size; Static := True; else Bounds_Utilities.Enumeration_Range (Element, Lbound, Ubound); Result := Enumeration_Type_Size (Lbound, Ubound, Is_Packed); Static := Ubound >= Lbound; end if; exit; when Types.An_Integer_Type_Definition => Bounds_Utilities.Integer_Range_Constraint_Bounds (Types.Integer_Constraint (Element), Lbound, Ubound, Static); if Static then Result := Integer_Type_Size (Lbound, Ubound); end if; exit; when Types.A_Float_Type_Definition => Bounds_Utilities.Float_Range_Constraint_Bounds (Types.Floating_Point_Constraint (Element), L_Bound, U_Bound, Static); Expression_Value (Types.Digits_Accuracy_Definition (Element), Digits_Accuracy, Static); if Static then Result := Float_Type_Size (L_Bound, U_Bound, Digits_Accuracy); end if; exit; when Types.A_Task_Type_Definition => Result := Task_Type_Size; Static := True; Requires_Alignment := True; exit; when Types.A_Fixed_Type_Definition => Find_Fixed_Constraints (Root => Element, First => Element, Range_Constraint => Range_Constraint, Delta_Constraint => Delta_Constraint); Bounds_Utilities.Fixed_Range_Constraint_Bounds (Delta_Constraint, Range_Constraint, Lbound, Ubound, Static); if Static then Result := Integer_Type_Size (Lbound, Ubound, Is_Packed); exit; end if; when Types.An_Array_Type_Definition => if Types.Is_Constrained_Array (Element) then Array_Size (Element, Ignore_Rep_Clauses, Types.Index_Constraints (Element), Result, Static); else Result := 0; Static := False; end if; exit; when Types.An_Access_Type_Definition => Access_Size (Element, Result, Static); Requires_Alignment := True; exit; when Types.A_Record_Type_Definition => Record_Size (Element, Ignore_Rep_Clauses, Ada_Program.Nil_Element, Result, Requires_Alignment, Static); exit; when Types.A_Derived_Type_Definition => Element := Types.Last_Constraint (Types.Derived_From (Element)); -- loop on type that was derived when Types.A_Private_Type_Definition .. Types.A_Limited_Private_Type_Definition => Element := Declarations.Enclosing_Declaration (Element); Element := Ada_Program.Definition (Element); when Types.Not_A_Type_Definition => Result := 0; Static := False; exit; end case; else Expression_Value (Size_Expression, Result, Static); return; end if; end loop; end Size; procedure Size (Ref_Id : Ada_Program.Identifier_Reference := Ada_Program.Nil_Element; Ignore_Rep_Clauses : Boolean; Original : Type_Information.Type_Definition; Constraint : Type_Information.Type_Constraint; Result : out Long_Natural; Requires_Alignment : in out Boolean; Static : in out Boolean) is Ground : Types.Type_Definition := Types.Ground_Type (Original); Range_Constraint, Delta_Constraint : Types.Type_Constraint; Lbound, Ubound : Long_Integer; L_Bound, U_Bound : Float; Digits_Accuracy : Long_Natural; Is_Packed : Boolean; begin Requires_Alignment := False; case Types.Kind (Ground) is when Types.An_Enumeration_Type_Definition => Bounds_Utilities.Enumeration_Range_Constraint_Bounds (Constraint, Lbound, Ubound, Static); if Static then Result := Enumeration_Type_Size (Lbound, Ubound, Is_Packed); else Result := 0; end if; when Types.An_Integer_Type_Definition => Bounds_Utilities.Integer_Range_Constraint_Bounds (Constraint, Lbound, Ubound, Static); if Static then Result := Integer_Type_Size (Lbound, Ubound, Is_Packed); else Result := 0; end if; when Types.A_Fixed_Type_Definition => Find_Fixed_Constraints (Ref_Id => Ref_Id, Root => Constraint, First => Constraint, Range_Constraint => Range_Constraint, Delta_Constraint => Delta_Constraint); Bounds_Utilities.Fixed_Range_Constraint_Bounds (Delta_Constraint, Range_Constraint, Lbound, Ubound, Static); if Static then Result := Integer_Type_Size (Lbound, Ubound, Is_Packed); else Result := 0; end if; when Types.A_Float_Type_Definition => Bounds_Utilities.Float_Range_Constraint_Bounds (Constraint, L_Bound, U_Bound, Static); Expression_Value (Types.Digits_Accuracy_Definition (Ground), Digits_Accuracy, Static); if Static then Result := Float_Type_Size (L_Bound, U_Bound, Digits_Accuracy); end if; when Types.An_Array_Type_Definition => Array_Size (Ground, Ignore_Rep_Clauses, Types.Discrete_Ranges (Constraint), Result, Static); when Types.A_Record_Type_Definition => Record_Size (Ground, Ignore_Rep_Clauses, Constraint, Result, Requires_Alignment, Static); when others => -- Can't happen ... Result := 0; Static := False; end case; end Size; procedure Type_Size (For_Type : Type_Information.Type_Definition; Ignore_Type_Representation_Clauses : Boolean := False; Result : out Long_Natural; Static : in out Boolean) is Exact_Size : Long_Natural; Requires_Alignment : Boolean; begin Size (For_Type, Ignore_Type_Representation_Clauses, Exact_Size, Requires_Alignment, Static); Result := Exact_Size; end Type_Size; procedure Object_Size (For_Object : Declarations.Object_Declaration; Ignore_Type_Representation_Clauses : Boolean := False; Result : out Long_Natural; Static : in out Boolean) is Exact_Size : Long_Natural; Requires_Alignment : Boolean; Number_Of_Id_Decls : Long_Natural; begin Number_Of_Ids (For_Object, Number_Of_Id_Decls); Size (Declarations.Object_Type (For_Object), Ignore_Type_Representation_Clauses, Exact_Size, Requires_Alignment, Static); if Requires_Alignment then Result := Number_Of_Id_Decls * Round_Up_To_Alignment (Exact_Size, Object_Declaration_Alignment); else Result := Number_Of_Id_Decls * Exact_Size; end if; end Object_Size; procedure Number_Of_Ids (Object : Declarations.Object_Declaration; Count : out Long_Natural) is Ids : Ada_Program.Element_List := Declarations.Identifiers (Object); Total : Long_Natural := 0; begin while not Ada_Program.Done (Ids) loop Total := Total + 1; Ada_Program.Next (Ids); end loop; Count := Total; end Number_Of_Ids; end Size_Utilities;
nblk1=2e nid=0 hdr6=5c [0x00] rec0=20 rec1=00 rec2=01 rec3=030 [0x01] rec0=17 rec1=00 rec2=02 rec3=020 [0x02] rec0=1b rec1=00 rec2=03 rec3=096 [0x03] rec0=1a rec1=00 rec2=04 rec3=00e [0x04] rec0=1b rec1=00 rec2=05 rec3=010 [0x05] rec0=19 rec1=00 rec2=06 rec3=024 [0x06] rec0=00 rec1=00 rec2=2e rec3=00e [0x07] rec0=17 rec1=00 rec2=07 rec3=022 [0x08] rec0=18 rec1=00 rec2=08 rec3=01a [0x09] rec0=00 rec1=00 rec2=2d rec3=016 [0x0a] rec0=17 rec1=00 rec2=09 rec3=046 [0x0b] rec0=00 rec1=00 rec2=2c rec3=010 [0x0c] rec0=17 rec1=00 rec2=0a rec3=050 [0x0d] rec0=1e rec1=00 rec2=0b rec3=00c [0x0e] rec0=00 rec1=00 rec2=2b rec3=01a [0x0f] rec0=1a rec1=00 rec2=0c rec3=034 [0x10] rec0=00 rec1=00 rec2=2a rec3=00e [0x11] rec0=15 rec1=00 rec2=0d rec3=06e [0x12] rec0=00 rec1=00 rec2=29 rec3=012 [0x13] rec0=16 rec1=00 rec2=0e rec3=008 [0x14] rec0=00 rec1=00 rec2=28 rec3=012 [0x15] rec0=1c rec1=00 rec2=0f rec3=000 [0x16] rec0=15 rec1=00 rec2=10 rec3=03a [0x17] rec0=00 rec1=00 rec2=27 rec3=038 [0x18] rec0=17 rec1=00 rec2=11 rec3=064 [0x19] rec0=18 rec1=00 rec2=12 rec3=02c [0x1a] rec0=00 rec1=00 rec2=26 rec3=01a [0x1b] rec0=1b rec1=00 rec2=13 rec3=036 [0x1c] rec0=02 rec1=00 rec2=25 rec3=020 [0x1d] rec0=19 rec1=00 rec2=14 rec3=062 [0x1e] rec0=1d rec1=00 rec2=15 rec3=050 [0x1f] rec0=00 rec1=00 rec2=24 rec3=018 [0x20] rec0=14 rec1=00 rec2=16 rec3=042 [0x21] rec0=14 rec1=00 rec2=17 rec3=020 [0x22] rec0=12 rec1=00 rec2=18 rec3=046 [0x23] rec0=01 rec1=00 rec2=23 rec3=00a [0x24] rec0=13 rec1=00 rec2=19 rec3=06a [0x25] rec0=15 rec1=00 rec2=1a rec3=046 [0x26] rec0=17 rec1=00 rec2=1b rec3=08a [0x27] rec0=16 rec1=00 rec2=1c rec3=002 [0x28] rec0=13 rec1=00 rec2=1d rec3=03c [0x29] rec0=16 rec1=00 rec2=1e rec3=03a [0x2a] rec0=1a rec1=00 rec2=1f rec3=008 [0x2b] rec0=00 rec1=00 rec2=22 rec3=010 [0x2c] rec0=1a rec1=00 rec2=20 rec3=03c [0x2d] rec0=07 rec1=00 rec2=21 rec3=001 tail 0x215004478815c6606e31b 0x42a00088462061e03