protected static PSObject _CreateDbgValueWorker()

in DbgProvider/public/Debugger/DbgValue.cs [757:943]


        protected static PSObject _CreateDbgValueWorker( DbgSymbol symbol,
                                                         bool skipConversion,
                                                         bool skipDerivedTypeDetection,
                                                         bool followPointers,
                                                         out int numDerefs )
        {
            DbgSymbol valSymbol = symbol;
            numDerefs = 0;

            bool incrementedSkipVersion;
            if( skipConversion )
            {
                sm_skipConversionCount++;
                incrementedSkipVersion = true;
            }
            else
                incrementedSkipVersion = false;

            skipConversion = sm_skipConversionCount > 0;

            // Note that this is outside the try/catch, so that it if it throws, it will
            // bubble up and stop a user conversion script.
            _CheckForRunawayUserConversion( symbol );
            try
            {
                object val;

                DtdRecord dtdRecord = null;

                PSObject finalVal = null;

                // *sigh* I feel like this could be rewritten more elegantly if I had time
                // to detangle it.
                do
                {
                    if( valSymbol.IsValueUnavailable )
                    {
                        finalVal = new DbgUnavailableValue( valSymbol ).WrappingPSObject;
                        break;
                    }

                    // We need to try conversions before creating a DbgPointerValue
                    // (because some conversions may handle pointer values, like WCHAR*),
                    // but NOT if the pointer is NULL, so we handle NULL even before that.
                    if( valSymbol.IsPointer && (0 == valSymbol.ReadAs_pointer()) )
                    {
                        finalVal = _CreatePointerValue( valSymbol );
                        break;
                    }

                    //
                    // We shouldn't be able to make it around the loop after DTD has kicked in...
                    // TODO: unless SVC returns a pointer, and we decide to follow it?
                    //
                    Util.Assert( null == dtdRecord );

                    if( !skipDerivedTypeDetection && valSymbol.IsUdt )
                    {
                        var udtType = (DbgUdtTypeInfo) valSymbol.Type;
                        DbgUdtTypeInfo derivedType;
                        int offsetFromDerived = 0;

                        if( _TryDetectDerivedType( valSymbol, out derivedType, out offsetFromDerived ) )
                        {
                            var originalSym = valSymbol;
                            valSymbol = new DbgSimpleSymbol( valSymbol.Debugger,
                                                             valSymbol.Name,
                                                             derivedType,
                                                             (ulong) (((long) valSymbol.Address) + offsetFromDerived) );

                            dtdRecord = new DtdRecord( originalSym );
                        } // end if( we detected that the object was of a derived type )
                    } // end if( should attempt DTD )


                    bool isBitfield;
                    if( _TrySafeConversions( valSymbol, out val, out isBitfield ) )
                    {
                        // DTD should not ever apply to things that "safe conversions"
                        // apply to, so we don't need to worry about that here.
                        Util.Assert( null == dtdRecord );
                        finalVal = _CreateWrapperPso( valSymbol, val, isBitfield );
                        break;
                    }

                    string converterApplied = null;
                    if( !skipConversion && _TrySymbolValueConversion( valSymbol,
                                                                      out val,
                                                                      out converterApplied ) )
                    {
                        var pso = _CreateWrapperPso( valSymbol,
                                                     val,
                                                     isBitfield );

                        // The conversion could have returned anything (besides null)...

                        var svcRecord = new SvcRecord( converterApplied, valSymbol );

                        DbgValue dv = val as DbgValue;
                        if( null == dv )
                        {
                            dv = pso.BaseObject as DbgValue;
                        }

                        List< SymbolHistoryRecord > symbolHistory;

                        if( null != dv )
                        {
                            symbolHistory = dv.m_symbolHistory;
                        }
                        else
                        {
                            // *MUST* it be a PSO here? We can't get, say, a raw [boxed] int?

                            symbolHistory = ((dynamic) pso).DbgGetSymbolHistory();
                        }

                        LogManager.Trace( "Adding SVC record to transform history on a DbgValue." );
                        symbolHistory.Add( svcRecord );

                        if( null != dtdRecord )
                        {
                            LogManager.Trace( "Also adding dtdRecord to converted DbgValue." );
                            symbolHistory.Add( dtdRecord );
                        }

                        //
                        // Any other Derived Type Detection or Symbol Value Conversion
                        // should have been handled recursively... so we should be able to
                        // return here.
                        //
                        // TODO: what if conversion returned a pointer?? should we keep following it?
                        //

                        finalVal = pso;
                        break;
                    }

                    if( valSymbol.IsPointer )
                    {
                        // We can't follow some pointers (void*, function pointers).
                        if( followPointers && valSymbol.CanFollow )
                        {
                            Util.Assert( 1 == valSymbol.Children.Count );
                            valSymbol = valSymbol.Children[ 0 ]; // There should be one child: the pointee
                        }
                        else
                        {
                            // We should not have a dtdRecord here...
                            // TODO: unless SVC returned a pointer and we decided to keep chasing it?
                            Util.Assert( null == dtdRecord );
                            finalVal = _CreatePointerValue( valSymbol );
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }

                    numDerefs++;
                } while( followPointers );

                if( null == finalVal )
                    finalVal = DbgValue._CreateDbgValueTerminal( valSymbol, dtdRecord );

                // If we were following pointers, let's cache the value so that we don't
                // have to re-compute it again later.
                if( numDerefs > 0 )
                {
                    valSymbol.SetCachedValue( finalVal,
                                              skipConversion,
                                              skipDerivedTypeDetection );
                }

                return finalVal;
            }
            catch( DbgProviderException dpe )
            {
                return DbgValue._CreateDbgValueError( valSymbol, dpe );
            }
            finally
            {
                if( incrementedSkipVersion )
                    sm_skipConversionCount--;
            }
        } // end _CreateDbgValueWorker()