protected IDisposable SetDebuggerAndContextAndUpdateCallbacks(string contextPath) { if (String.IsNullOrEmpty(contextPath)) { PathInfo pi = this.CurrentProviderLocation(DbgProvider.ProviderId); contextPath = pi.ProviderPath; } else { contextPath = GetUnresolvedProviderPathFromPSPath(contextPath); } Debugger = DbgProvider.GetDebugger(contextPath); if ((null == Debugger) || Debugger.NoTarget) { throw new DbgProviderException("No target.", "NoTarget", ErrorCategory.InvalidOperation); } var inputCallbacks = Debugger.GetInputCallbacks() as DebugInputCallbacks; if (null != inputCallbacks) { inputCallbacks.UpdateCmdlet(this); } var disposable = Debugger.SetCurrentCmdlet(this); Debugger.SetContextByPath(contextPath); return(disposable); } // end SetDebuggerAndContextAndUpdateCallbacks()
protected override void ProcessRecord() { base.ProcessRecord(); // WriteObject( "\u009b91mThis should be red.\u009bm This should not.\r\n" ); // WriteObject( "\u009b91;41mThis should be red on red.\u009bm This should not.\r\n" ); // WriteObject( "\u009b91;100mThis should be red on gray.\u009b" ); // WriteObject( "m This should not.\r\n" ); // WriteObject( "\u009b" ); // WriteObject( "9" ); // WriteObject( "1;10" ); // WriteObject( "6mThis should be red on cyan.\u009b" ); // WriteObject( "m This should \u009bm\u009bmnot.\r\n" ); // //WriteObject( "\u009b92mModLoad:\u009bm 758a0000 758ac000 \u009b97mCRYPTBASE\u009bm\r\n" ); // //WriteObject( "\u009b92mModLoad:\u009bm 758a0000 758ac000 \u009b30;107mCRYPTBASE\u009bm\r\n" ); PathInfo pi = this.CurrentProviderLocation(DbgProvider.ProviderId); var debugger = DbgProvider.GetDebugger(pi.ProviderPath); debugger.SetContextByPath(pi.ProviderPath); } // end ProcessRecord()
protected override void ProcessRecord() { base.ProcessRecord(); PathInfo pi = this.CurrentProviderLocation(DbgProvider.ProviderId); var debugger = DbgProvider.GetDebugger(pi.ProviderPath); debugger.SetContextByPath(pi.ProviderPath); WDebugSymbols ds = (WDebugSymbols)debugger.DebuggerInterface; } // end ProcessRecord()
public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) { object originalInputData = inputData; var pso = inputData as PSObject; if (null != pso) { inputData = pso.BaseObject; } if (inputData is DbgTypeInfo) { return(inputData); } string path = engineIntrinsics.SessionState.Path.CurrentProviderLocation(DbgProvider.ProviderId).ProviderPath; var debugger = DbgProvider.GetDebugger(path); Exception e = null; string str = inputData as string; if (null != str) { try { // TODO: Would be nice to ask the PowerShell team to plumb cancellation support // through parameter transformation. var types = debugger.GetTypeInfoByName(str, System.Threading.CancellationToken.None).ToList(); if (null != types) { if (types.Count > 1) { engineIntrinsics.InvokeCommand.InvokeScript(Util.Sprintf("Write-Warning 'Multiple types found for name \"{0}\".'", str)); LogManager.Trace("Warning: TypeTransformationAttribute: found multiple types for name '{0}'.", str); } else if (0 != types.Count) { return(types[0]); } } } catch (DbgProviderException dpe) { e = dpe; } } // end if( it's a string ) throw CreateRecoverableAtme(e, "Type not found. (Could not convert '{0}' to a type.)", originalInputData); } // end Transform()
public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) { object originalInputData = inputData; var pso = inputData as PSObject; if (null != pso) { inputData = pso.BaseObject; } if (inputData is string) { return(inputData); } if (inputData is DbgModuleInfo) { return(((DbgModuleInfo)inputData).ImageName); } string path = engineIntrinsics.SessionState.Path.CurrentProviderLocation(DbgProvider.ProviderId).ProviderPath; var debugger = DbgProvider.GetDebugger(path); Exception e = null; // Maybe it is an address? try { object addrObj = AddressTransformationAttribute.Transform( engineIntrinsics, null, true, // skipGlobalSymbolTest false, // throwOnFailure originalInputData); if (null != addrObj) { var mod = new DbgModuleInfo(debugger, (ulong)addrObj, debugger.GetCurrentTarget()); return(mod.Name); } } catch (DbgEngException dee) { e = dee; } throw CreateRecoverableAtme(e, "Could not convert '{0}' to a module name.", originalInputData); } // end Transform()
} // end _TryConvertToUint() public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) { object originalInputData = inputData; var pso = inputData as PSObject; if (null != pso) { inputData = pso.BaseObject; } if (inputData is DbgUModeThreadInfo) { return(inputData); } if (null == inputData) { // Some commands CAN take a thread, but don't require it. return(null); } var type = inputData.GetType(); if (type.IsArray) { Array asArray = (Array)inputData; DbgUModeThreadInfo[] threads = new DbgUModeThreadInfo[asArray.Length]; for (int i = 0; i < threads.Length; i++) { threads[i] = Transform(engineIntrinsics, asArray.GetValue(i)) as DbgUModeThreadInfo; if (null == threads[i]) { // Array embedded within an array? Not going to handle that. throw new ArgumentTransformationMetadataException(Util.Sprintf("Could not convert item at index {0} to a thread.", i)); } } return(threads); } // end if( array ) DbgUModeThreadInfo thread = null; uint tid; if (_TryConvertToUint(engineIntrinsics, originalInputData, out tid)) { string path = engineIntrinsics.SessionState.Path.CurrentProviderLocation(DbgProvider.ProviderId).ProviderPath; var debugger = DbgProvider.GetDebugger(path); try { thread = debugger.GetUModeThreadByDebuggerId(tid); return(thread); } catch (DbgProviderException) { // ignore } // Maybe it's a system tid? // I wonder if this "helpfulness" actually confuses things... try { thread = debugger.GetThreadBySystemTid(tid); return(thread); } catch (DbgProviderException) { // ignore } throw new ArgumentTransformationMetadataException(Util.Sprintf("No such thread: {0}.", tid)); } throw CreateRecoverableAtme("Could not convert '{0}' to a thread.", originalInputData); } // end Transform()
public override object Transform(EngineIntrinsics engineIntrinsics, object inputData) { object originalInputData = inputData; var pso = inputData as PSObject; if (null != pso) { inputData = pso.BaseObject; } if (inputData is DbgModuleInfo) { return(inputData); } if (null == inputData) { return(null); } string path = engineIntrinsics.SessionState.Path.CurrentProviderLocation(DbgProvider.ProviderId).ProviderPath; var debugger = DbgProvider.GetDebugger(path); Exception e = null; string str = inputData as string; if (null != str) { if (0 == str.Length) { return(null); } try { var foundMod = debugger.Modules.FirstOrDefault((m) => 0 == Util.Strcmp_OI(m.Name, str)); if (null != foundMod) { return(foundMod); } } catch (DbgProviderException dpe) { e = dpe; } } if (null == e) { // Maybe it was an address... try { object addrObj = AddressTransformationAttribute.Transform( engineIntrinsics, null, true, // skipGlobalSymbolTest false, // throwOnFailure originalInputData); if (null != addrObj) { return(new DbgModuleInfo(debugger, (ulong)addrObj, debugger.GetCurrentTarget())); } } catch (DbgEngException dee) { e = dee; } } throw CreateRecoverableAtme(e, "Could not convert '{0}' to a module.", originalInputData); } // end Transform()
// You must pass either the engineIntrinsics, or the path. (You don't need both.) // This is a hacky-wacky workaround for the fact that there's no way for user code // to get an EngineIntrinsics object, but I want user code to be able to call this // method directly, and I don't want everyone to /always/ have to get the path. public static object Transform(EngineIntrinsics engineIntrinsics, string dbgProviderPath, bool skipGlobalSymbolTest, bool throwOnFailure, bool dbgMemoryPassthru, bool allowList, object inputData) { //Console.WriteLine( "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv" ); //Console.WriteLine( "{0} 1: inputData type: {1}", DebuggingTag, inputData.GetType().FullName ); //Console.WriteLine( "{0} 2: dynamic type: {1}", DebuggingTag, ((dynamic) inputData).GetType().FullName ); //Console.WriteLine( "{0} 3: ToString(): {1}", DebuggingTag, inputData.ToString() ); //Console.WriteLine( "{0} 4: dynamic ToString(): {1}", DebuggingTag, ((dynamic) inputData).ToString() ); var pso = inputData as PSObject; if (allowList) { var objList = inputData as IList; if ((null != pso) && (pso.BaseObject is IList)) { objList = (IList)pso.BaseObject; } if (null != objList) { ulong[] addrs = new ulong[objList.Count]; try { for (int i = 0; i < objList.Count; i++) { addrs[i] = (ulong)Transform(engineIntrinsics, dbgProviderPath, skipGlobalSymbolTest, true, // throwOnFailure, dbgMemoryPassthru, false, // we don't allow nested arrays objList[i]); } // end for( each obj ) return(addrs); } catch (Exception e_temp) { if (throwOnFailure || (!(e_temp is DbgProviderException) && !(e_temp is MetadataException))) { throw; } } } // end if( it's an array ) } // end if( allowList ) if (null != pso) { // Addresses are always expressed in hexadecimal. // // Thus you can type a leading "0x", but it is redundant and not // necessary. // // If the address contains a backtick, or for some reason is expressed in // decimal with a leading "0n", or has hex-only digits ([a-f]) but no // leading "0x", then PowerShell will parse it as a string. Then we can // handle parsing it ourselves (in this method). // // However... if the user /did/ use a leading "0x" and there is no // backtick, OR if the address contains no hex-only digits and there is no // backtick, OR if the address ended with "eN" (where N is a digit)... // then PowerShell will have parsed it as a number (giving us either an // UInt32, or a UInt64, or a double, depending on how big). // // In that case, we need to figure out whether or not the user typed an // "0x", because if they did not, that means that PowerShell parsed it // incorrectly (as a base-10 number, and possibly using scientific // notation, instead of a base-16 number). // // Fortunately, if we have the PSObject for that typed number, we can get // the originally typed string, which will let us know if there was an // "0x" or not. // // Update: "if we have the PSObject for that typed number, we can get the // originally typed string": unfortunately, that is not always true, such // as when the address is piped in. TODO: can we change PowerShell to // allow us to get the string as originally typed in more cases? //Console.WriteLine( "{0} 5: BaseObject type: {1}", DebuggingTag, pso.BaseObject.GetType().FullName ); if ((pso.BaseObject is int) || (pso.BaseObject is long) || (pso.BaseObject is double) || (pso.BaseObject is float)) { // The standard way to get the originally typed string is to use // LanguagePrimitives.ConvertTo< string >. However, it seems that it // wants to /always/ give us a string back, even if it doesn't have // the originally typed string. So if we use that method, we don't // know if the string we get back actually is what was originally // typed or not. //var asTyped = LanguagePrimitives.ConvertTo< string >( pso ); // This /will/ get what the user actually typed (if it was typed), // but relies on reflection to get at PS internals. :( var asTyped = _GetAsTyped_usingIckyPrivateReflection(pso); //Console.WriteLine( "As typed: {0}", asTyped ); if (null != asTyped) { if (asTyped.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) { // Yes, they typed an "0x", so PS correctly parsed as hex. // // The cast to (int) first is to un-box. Then to (uint) to // prevent sign extension. if (pso.BaseObject is int) { return((ulong)(uint)(int)pso.BaseObject); } if (pso.BaseObject is long) { return(unchecked ((ulong)(long)pso.BaseObject)); } // Should not reach here. Util.Fail("How could the typed string start with 0x but get parsed as something besides an int or long?"); } inputData = asTyped; // we'll re-parse it below as base-16 } else { // If we get here, then it /was/ typed, but piped in: // // 01234000 | ConvertTo-Number // 0x01234000 | ConvertTo-Number // // So PS parsed it... but if we ended up with an integer type, we // don't know if it parsed as decimal or hex, so we can't be sure // how to undo that parsing. :( For now we'll have to just assume // that the user knows that they need to use 0x when piping in. // // That sounds bad, because actually a user probably will /not/ // know that, but the alternative is worse; a user who directly // specifies hex ("0x01230000 | something") should never get the // wrong result. // // TODO: see if we can get PS to preserve the as-typed value for // things that are piped in. inputData = pso.BaseObject; } } else { inputData = pso.BaseObject; } } //Console.WriteLine( "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" ); if (dbgMemoryPassthru && (inputData is DbgMemory)) { return(inputData); } // Some commands do not require an address. if (null == inputData) { return((ulong)0); } if (inputData is ulong) { return(inputData); } // We used to assume that this was probably a base-16 number without any // letters in it, so PS interpreted it as a base-10 number, so then we would // undo that. And hope it was right. But unfortunately, that messed up the // scenario where you assign a number to a variable ("$blah = 123"), so I'm // going the other way now--we'll assume it's already correct. Unfortunately, // that means that on 32-bit, you'll need to always use "0x" to be safe. :( // if( (inputData is int) || (inputData is long) ) // { // inputData = inputData.ToString(); // } if (inputData is int) { return((ulong)(uint)(int)inputData); // 1st cast unboxes; 2nd prevents sign extension } if (inputData is long) { return((ulong)(long)inputData); // need two casts in order to unbox first. } if (inputData is uint) { // This can happen, for instance, when using the register variables for a // 32-bit process ("u $eip"). return((ulong)(uint)inputData); // need two casts in order to unbox first. } if (inputData is byte) { // This can happen because we [ab]use AddressTransformationAttribute to // convert lots of numeric data, not just addresses. (For instance, the // "eb" command.) return((ulong)(byte)inputData); // need two casts in order to unbox first. } if (inputData is double) { // This can happen when doing arithmetic. For instance, this will yield // Double: // // [UInt32] $ui1 = 0x03 // [UInt32] $ui2 = 0x01 // ($ui2 - $ui1).GetType() // // To determine if it's really something that can be represented as a // ulong, we'll round-trip it through a ulong back to a double, and then // see if the bits representation matches the original double. double dOrig = (double)inputData; Int64 origBits = BitConverter.DoubleToInt64Bits(dOrig); unchecked { ulong asUlong = (ulong)(long)dOrig; double d2 = Convert.ToDouble((long)asUlong); Int64 d2Bits = BitConverter.DoubleToInt64Bits(d2); if (d2Bits == origBits) { // We round-tripped back to double: it doesn't have any fractional // part. return(asUlong); } } } // end if( inputData is double ) Exception e = null; string str = inputData as string; if (null != str) { // Some commands do not require an address. if (0 == str.Length) { return((ulong)0); } if ((1 == str.Length) && (str[0] == '.')) { dbgProviderPath = _GetDbgProviderPath(dbgProviderPath, engineIntrinsics); var regSet = DbgProvider.GetRegisterSetForPath(dbgProviderPath); return(regSet.Pseudo["$ip"].Value); } ulong address; if (DbgProvider.TryParseHexOrDecimalNumber(str, out address)) { return(address); } // Mabye it's a symbolic name? if (!skipGlobalSymbolTest) { dbgProviderPath = _GetDbgProviderPath(dbgProviderPath, engineIntrinsics); var debugger = DbgProvider.GetDebugger(dbgProviderPath); try { address = debugger.GetOffsetByName(str); return(address); } catch (DbgProviderException dpe) { e = dpe; } } } // Check for implicit conversion to ulong. (For instance, types that derive // from DbgPointerValueBase have this.) ulong addr; if (_TryImplicitConversionTo(inputData, out addr)) { return(addr); } if (!throwOnFailure) { return(null); } if (null != e) { ExceptionDispatchInfo.Capture(e).Throw(); } // https://github.com/PowerShell/PowerShell/issues/7600 // // For parameter binding to be able to continue (for example, to try binding // by property name), this exception needs to wrap a PSInvalidCastException. throw CreateRecoverableAtme("Could not convert '{0}' to an address.", inputData); } // end Transform()