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()