Exemple #1
0
        private void _FindPossibleOffsetsFromDerivedClass(DbgUdtTypeInfo baseType,
                                                          int curOffset,
                                                          List <int> offsets)
        {
            // Breadth-first search.
            foreach (var bc in BaseClasses)
            {
                if (bc._DuckTypeEquals(baseType))
                {
                    int offset = curOffset - (int)bc.Offset;  // relative to derived class!
                    offsets.Add(offset);
                    // I think I could actually break out of this loop here, but I'm too
                    // chicken.
                }
            }

            foreach (var bc in BaseClasses)
            {
                int tmpOffset = curOffset;
                tmpOffset -= (int)bc.Offset;  // relative to derived class!
                bc._FindPossibleOffsetsFromDerivedClass(baseType,
                                                        tmpOffset,
                                                        offsets);
            }
        } // end _FindPossibleOffsetsFromDerivedClass()
Exemple #2
0
        } // end _DuckTypeEquals()

        public List <int> FindPossibleOffsetsFromDerivedClass(DbgUdtTypeInfo baseType)
        {
            var offsets = new List <int>();

            _FindPossibleOffsetsFromDerivedClass(baseType, 0, offsets);
            return(offsets);
        }
Exemple #3
0
        // Unfortunately type information in PDBs expose us to the messy world of the
        // linker, where types have to match up across modules by name. (In other words,
        // every module has its own type information for IUnknown; or, IUnknown has a
        // different typeId in every module.) Sometimes we need to be able to make the
        // link between type information across modules (i.e.
        // TestNativeConsoleApp!IXmlReader == XmlLite!IXmlReader) in order to jump the gap
        // between declared types and implementing types. We do this in the same spirit as
        // "Duck Typing": if it looks like a duck, sounds like a duck...
        private bool _DuckTypeEquals(DbgUdtTypeInfo other)
        {
            if (Size != other.Size)
            {
                return(false);
            }

            if (0 == Util.Strcmp_OI(Name, other.Name))
            {
                // TODO: Should we add any other points of comparison? Members? Perhaps
                // we should add some more to help detect bugs (in the target, where,
                // for instance, mismatched binaries could lead to mismatched types).
                return(true);
            }

            foreach (var equivSet in sm_interfaceNameEquivalences)
            {
                if (equivSet.Contains(Name) &&
                    equivSet.Contains(other.Name))
                {
                    LogManager.Trace("_DuckTypeEquals: Special case: {0} is equivalent to {1}.",
                                     Name,
                                     other.Name);
                    return(true);
                }
            }

            // TODO: Try stripping __abi_ off?

            return(false);
        } // end _DuckTypeEquals()
Exemple #4
0
        } // end _EnsureInitialized()

        public static bool TryFindPossibleOffsetFromDerivedClass(DbgEngDebugger debugger,
                                                                 ulong vtableAddr,
                                                                 ulong firstSlotPtr,
                                                                 DbgUdtTypeInfo derivedType,
                                                                 DbgUdtTypeInfo baseType,
                                                                 out int offset)
        {
            _EnsureInitialized();

            foreach (var plugin in sm_dtdPlugins)
            {
                using (var logger = new LogAdapter(plugin.Name))
                {
                    if (plugin.TryFindPossibleOffsetFromDerivedClass(debugger,
                                                                     logger,
                                                                     vtableAddr,
                                                                     firstSlotPtr,
                                                                     derivedType,
                                                                     baseType,
                                                                     out offset))
                    {
                        LogManager.Trace("Possible offset from derived class ({0}{1:x}) found by plugin: {2}",
                                         offset > 0 ? "0x" : "",
                                         offset,
                                         plugin.Name);
                        return(true);
                    }
                }
            } // end foreach( plugin )

            // No plugin could figure it out.
            offset = 0;
            return(false);
        } // end TryFindPossibleOffsetFromDerivedClass()
Exemple #5
0
        } // end GetHashCode()

        #endregion IEquatable stuff


        /// <summary>
        ///    Finds the offset for a given member/member path from the start of the
        ///    specified type. (memberPath can contain dots, drilling into members)
        /// </summary>
        public uint FindMemberOffset(string memberPath)
        {
            uint offset = 0;

            string[]       memberNames = memberPath.Split('.');
            DbgUdtTypeInfo curType     = this;

            for (int idx = 0; idx < memberNames.Length; idx++)
            {
                string memberName = memberNames[idx];

                if (!curType.Members.HasItemNamed(memberName))
                {
                    throw new ArgumentException(Util.Sprintf("'{0}' does not have a member called '{1}'.",
                                                             FullyQualifiedName,
                                                             memberName),
                                                "memberPath");
                }

                var member = curType.Members[memberName];

                offset += member.Offset;

                bool notLastTime = idx < (memberNames.Length - 1);
                if (notLastTime)
                {
                    if (member.DataType is DbgPointerTypeInfo)
                    {
                        throw new ArgumentException(Util.Sprintf("There can't be a pointer in the memberPath ('{0}').",
                                                                 memberName),
                                                    "memberPath");
                    }

                    curType = member.DataType as DbgUdtTypeInfo;
                    if (null == curType)
                    {
                        throw new Exception(Util.Sprintf("Unexpected DataType: '{0}' is a {1}, not a UDT.",
                                                         memberName,
                                                         member.DataType.GetType().FullName));
                    }
                } // end if( not the last one )
            }     // end for( each memberName )

            return(offset);
        } // end FindMemberOffset
Exemple #6
0
        public IReadOnlyList <DbgTemplateNode> GetTemplateNodes()
        {
            if (null == m_templateNodes)
            {
                var templateTypeNames = new List <DbgTemplateNode>();
                DbgArrayTypeInfo ati  = this as DbgArrayTypeInfo;
                if (null != ati)
                {
                    templateTypeNames.Add(DbgTemplateNode.CrackTemplate(ati.ArrayElementType.Name + "[]"));     // we don't want the dimensions
                    // TODO: And maybe for array types, we'd like to include the array type /with/ dimensions,
                    // so that, for instance, all Foo[8] could be treated specially or something. But maybe that's
                    // stretching it.

                    // TODO: How about co-(or is it contra-)variance? (should we get base types of the element type, like we do for pointers?)
                }
                else if (typeof(DbgUdtTypeInfo).IsAssignableFrom(GetType()))
                {
                    DbgUdtTypeInfo uti = (DbgUdtTypeInfo)this;
                    templateTypeNames.Add(uti.TemplateNode);
                    _AddBaseClassNodesToList(templateTypeNames, uti);
                }
                else if (typeof(DbgPointerTypeInfo).IsAssignableFrom(GetType()))
                {
                    DbgPointerTypeInfo pti = (DbgPointerTypeInfo)this;
                    templateTypeNames.Add(pti.TemplateNode);
                    _AddBaseClassPointerNodesToList(templateTypeNames, pti);
                }
                else
                {
                    templateTypeNames.Add(DbgTemplateNode.CrackTemplate(Name));
                }

                m_templateNodes = templateTypeNames.AsReadOnly();
            }
            return(m_templateNodes);
        } // end GetTemplateNodes()
Exemple #7
0
        } // end GetTemplateNodes()

        private void _AddBaseClassNodesToList(List <DbgTemplateNode> list, DbgUdtTypeInfo uti)
        {
            uti.VisitAllBaseClasses((bc) => list.Add(bc.TemplateNode));
        } // end _AddBaseClassNodesToList()
        public bool TryFindPossibleOffsetFromDerivedClass(DbgEngDebugger debugger,
                                                          ILogger logger,
                                                          ulong vtableAddr,
                                                          ulong firstSlotPtr,
                                                          DbgUdtTypeInfo derivedType,   // AKA the implementing type
                                                          DbgUdtTypeInfo baseType,      // AKA the declaredType
                                                          out int offset)
        {
            offset = 0;

            List <int> possibleOffsets = derivedType.FindPossibleOffsetsFromDerivedClass(baseType);

            if (0 == possibleOffsets.Count)
            {
                //
                // Special case: if we are crossing module boundaries, but the type names
                // are the same, one module may have just a "stub" type definition
                // (vtables but no other members). In that case, we'll assume that the
                // offset is 0.
                //

                if (0 == Util.Strcmp_OI(derivedType.Name, baseType.Name))
                {
                    Util.Assert(derivedType.Module != baseType.Module);

                    LogManager.Trace("Type match between modules: {0} -> {1}",
                                     baseType.Module.Name,
                                     derivedType.Module.Name);

                    offset = 0;
                    return(true);
                }

                LogManager.Trace("Could not find a relationship between {0} (declared) and {1} (alleged concrete/derived).",
                                 baseType.Name,
                                 derivedType.Name);
                // It could just be because we're looking at garbage data.
                return(false);
            }
            else if (1 == possibleOffsets.Count)
            {
                offset = possibleOffsets[0];
                return(true);
            }
            else
            {
                LogManager.Trace("Thre are {0} possible offsets: {1}",
                                 possibleOffsets.Count,
                                 String.Join(", ", possibleOffsets));
                // This can happen, for instance, in the "manual IUnknown" case. We could
                // have multiple positions where IUnknown shows up, and we're not sure
                // which one we have:
                //
                //    > $t
                //    ieframe!CTabProcessReference (size 0x48)
                // -->   +0x000 CRefThread: VTable for IUnknown (rel. offset 0, 3 slots)
                //       +0x004 _pcRef              : Int4B*
                //       +0x008 _idThread           : UInt4B
                //       +0x00c _fProcessReference  : bool
                //       +0x010 _cDestructs         : Int4B
                // -->   +0x014 IWaitOnThreadsBeforeExit: VTable for IUnknown (rel. offset 0, 3 slots)
                //       +0x018 _dsaThreadsToWaitOn : CDSA<void *>
                //       +0x020 _tLastPrune         : UInt8B
                //       +0x028 _fInDestructor      : bool
                //       +0x02c _csDSA              : _RTL_CRITICAL_SECTION
                //
                // If there are multiple possibilities, some of them will point to
                // "adjustor thunks" (see
                // http://blogs.msdn.com/b/oldnewthing/archive/2004/02/06/68695.aspx).
                // There isn't any symbolic way to get the info, so we fall back once
                // again to parsing it out of a symbol name.
                //
                if (_TryDiscernOffsetFromAdjustorThunk(debugger, firstSlotPtr, out offset))
                {
                    Util.Assert(possibleOffsets.Contains(offset));
                    return(true);
                }
                LogManager.Trace("_TryDetectDerivedType: Multiple possible offsets; couldn't pick one, between {0} (declared) and {1} (alleged concrete/derived).",
                                 baseType.Name,
                                 derivedType.Name);
                return(false);
            } // end multiple possible offsets
        }     // end TryFindPossibleOffsetFromDerivedClass()
            private static List <LayoutItem> _BuildList(DbgUdtTypeInfo udt,
                                                        bool sortByOffset)
            {
                var vtables = udt.FindVTables().ToList();
                var list    = new List <LayoutItem>(vtables.Count + udt.Members.Count);

                if (sortByOffset)
                {
                    // This is NOT how windbg does things. In windbg, in the face of
                    // unions, you'll see something like offsets 0, 4, 8, then 0, 4, 8
                    // again, etc.; similar to how the type is declared.
                    //
                    // Here, the caller has exercised the option to sort everything by
                    // offset instead. List.Sort is unstable, but we added a stabilizing
                    // factor in LayoutItem's IComparable implementation. This allows us
                    // to keep things in mostly the same order as would be displayed by
                    // windbg.
                    int idx = 0;
                    foreach (var vtr in vtables)
                    {
                        list.Add(new VTableLayoutItem(vtr, idx));
                        idx++;
                    }

                    foreach (var mem in udt.Members)
                    {
                        list.Add(new LayoutItem((int)mem.Offset, mem, idx));
                        idx++;
                    }

                    list.Sort();
                }
                else
                {
                    // (this should result in the same order as windbg displays)
                    //
                    // The members are already in the proper order. We just need to slip
                    // the vtable entries in. I'll slip them in as if the list was sorted
                    // by offset. (but actually... is that what windbg does? I need to
                    // find some exotic vtable examples)
                    int memIdx = 0;
                    foreach (var vt in vtables)
                    {
                        var vtli = new VTableLayoutItem(vt, 0);
                        while ((memIdx < udt.Members.Count) &&
                               (vt.TotalOffset > udt.Members[memIdx].Offset))
                        {
                            list.Add(new LayoutItem((int)udt.Members[memIdx].Offset,
                                                    udt.Members[memIdx],
                                                    memIdx));
                            memIdx++;
                        }
                        list.Add(vtli);
                    }

                    // Finish the rest.
                    for ( ; memIdx < udt.Members.Count; memIdx++)
                    {
                        list.Add(new LayoutItem((int)udt.Members[memIdx].Offset,
                                                udt.Members[memIdx],
                                                memIdx));
                    }
                }

                return(list);
            } // end _BuildList()
 internal InstanceLayout(DbgUdtTypeInfo udt, bool sortByOffset)
 {
     Items      = new ReadOnlyCollection <LayoutItem>(_BuildList(udt, sortByOffset));
     m_udt      = udt;
     m_isSorted = sortByOffset;
 }