List TraverseTpmStructure()

in Tpm2Tester/TestSubstrate/TestFuzzer.cs [1294:1419]


        List<FuzzableMember> TraverseTpmStructure(Type t, object o, FieldFilter filter)
        {
            var fuzzableVals = new List<FuzzableMember>();

            if (o == null)
            {
                return fuzzableVals;
            }

            // recurse
            var members = new List<MemberInfo>();
            foreach (var bf in new BindingFlags[] {BindingFlags.Public, BindingFlags.NonPublic})
            {
                var candidateMembers = t.GetMembers(BindingFlags.Instance | bf);
                foreach (var mi in candidateMembers)
                {
                    var memberAttrs = mi.CustomAttributes;
                    foreach (var a in memberAttrs)
                    {
                        if (a.AttributeType.Name != "MarshalAsAttribute")
                        {
                            continue;
                        }
                        var arg1 = a.ConstructorArguments[1];
                        if (arg1.ArgumentType == typeof(MarshalType))
                        {
                            var marshalType = (MarshalType)arg1.Value;
                            if (marshalType != MarshalType.ArrayCount &&
                                marshalType != MarshalType.LengthOfStruct &&
                                marshalType != MarshalType.UnionSelector)
                            {
                                members.Add(mi);
                            }
                        }
                        break;
                    }
                }
            }

            FuzzDbg.Trace(t.ToString());
            FuzzDbg.Indent();
            foreach (var memInfo in members)
            {
                Type memType = Globs.GetMemberType(memInfo);
                object member = Globs.GetMember(memInfo, o);

                if (member == null)
                {
                    if (!filter.HasFlag(FieldFilter.NonNull))
                    {
                        // TODO: Update CmdComplexity based on the type info
                        fuzzableVals.Add(new FuzzableMember(memInfo, o, 0));
                        if (memInfo.Name != "inPrivate")
                            FuzzDbg.Trace("Leaf 'Nil': {0} {1}", memType, memInfo.Name);
                    }
                    continue;
                }

                Type actualType = member.GetType();
                if (actualType.GetTypeInfo().IsSubclassOf(typeof(TpmStructureBase)))
                {
                    // TODO: Update CmdComplexity based on the type info
                    FuzzDbg.Trace("Tpm Structure: {0} {1} {2}", memType, actualType, memInfo.Name);
                    fuzzableVals.AddRange(TraverseTpmStructure(actualType, member, filter));
                    RememberValidStruct(memType, member);
                }
                else if (actualType.IsArray && actualType != typeof(byte[]))
                {
                    FuzzDbg.Trace("Array: {0} {1} {2}", memType, actualType, memInfo.Name);
                    var arr = (Array)member;
                    Type elementType = actualType.GetElementType();
                    foreach (object e in arr)
                    {
                        fuzzableVals.AddRange(TraverseTpmStructure(elementType, e, filter));
                    }
                    RememberValidStruct(memType, member);
                }
                else if (  !filter.HasFlag(FieldFilter.Buffer)
                         || actualType == typeof(byte[]))
                {
                    int complexity = 0;
                    if (actualType.GetTypeInfo().IsEnum)
                    {
                        complexity = Enum.GetValues(actualType).Length / 4 + 4;
                        if (memInfo is PropertyInfo)
                        {
                            Type uType = Enum.GetUnderlyingType(actualType);
                            object origVal = Convert.ChangeType(member, uType);
                            Globs.SetMember(memInfo, o, Enum.ToObject(actualType,
                                            Globs.IncrementValue(origVal, 1)));
                            object newVal = Convert.ChangeType(
                                                Globs.GetMember(memInfo, o), uType);
                            if (newVal.Equals(origVal))
                            {
                                // A property without setter
                                FuzzDbg.Trace("Property w/o setter: {0} {1}", actualType, memInfo.Name);
                                continue;
                            }
                        }
                    }
                    else if (actualType == typeof(byte[]))
                    {
                        complexity = 16;
                    }
                    else if (o.GetType() == typeof(TpmHandle))
                    {
                        // TPM_RH, PCR, transient, persistent, NV, session, arbitrary 
                        complexity = Enum.GetValues(typeof(TpmRh)).Length / 4 + 6 * 2;
                    }
                    else
                    {
                        // An integer value
                        complexity = 4;
                    }
                    FuzzDbg.Trace("Leaf '{0}': {0} {1}", filter.HasFlag(FieldFilter.Buffer) ? "Buf" : "Val", actualType, memInfo.Name);
                    CmdComplexity += complexity;
                    fuzzableVals.Add(new FuzzableMember(memInfo, o, complexity));
                }
                else
                {
                    Debug.Assert("Unidentified field type" == "");
                }
            }
            FuzzDbg.Unindent();
            return fuzzableVals;
        }