} // end GenerateView()

        protected override void ApplyViewToInputObject()
        {
            for (int idx = 0; idx < m_view.ListItems.Count; idx++)
            {
                if (Stopping)
                {
                    break;
                }

                ColorString listItem = new ColorString(sm_labelColors);

                ListItem li = m_view.ListItems[idx];
                listItem.Append(PadAndAlign(li.Label,
                                            m_view.MaxLabelLength + 1,
                                            ColumnAlignment.Left) + ": ");

                listItem.Append(sm_pop.ToString(DbgProvider.HostSupportsColor));

                string val;
                if (li is PropertyListItem)
                {
                    var pli = (PropertyListItem)li;
                    val = RenderPropertyValue(InputObject,
                                              pli.PropertyName,
                                              pli.FormatString);
                }
                else
                {
                    var sli = (ScriptListItem)li;
                    val = RenderScriptValue(InputObject, sli.Script);
                    if (null == val)
                    {
                        val = String.Empty;
                    }
                }

                listItem.Append(_Indent(val));
                SafeWriteObject(listItem);
            }
            // N.B. Using String.Empty here used to cause 3 blank lines instead of one.
            // I don't understand precisely why, but the crux of the problem is that
            //
            //     a) System.String has a custom view definition (which is to get around
            //        PowerShell's reticence to properly display strings if they have
            //        other stuff in their TypeNames) (see commit 4bc7d1c76f97d0)
            //     b) When we write the string here, for some reason it causes a
            //        transition between steppable pipelines, and the PS default
            //        formatter wants to put in an extra newline at the format start and
            //        another at the format end.
            //
            // Fortunately, it seems easy enough to workaround by sending a different type
            // of object down the pipeline.
            //
            // (I wonder if it might have been specific to the particular commands I was
            // using to test, like "uf blah!blah | fl", or symbols | fl, because of how
            // their formatting was done.)
            //
            //SafeWriteObject( String.Empty ); // to get a blank line
            SafeWriteObject(ColorString.Empty);   // to get a blank line
        } // end ApplyViewToInputObject()
        } // end ResetState()

        private void _WriteHeaders()
        {
            ColorString headers = new ColorString(sm_tableHeaderColors);

            // Write labels:
            for (int colIdx = 0; colIdx < m_view.Columns.Count; colIdx++)
            {
                Column c = m_view.Columns[colIdx];
                headers.Append(PadAndAlign(c.Label,
                                           c.CalculatedWidth,
                                           c.CalculatedAlignment,
                                           c.TrimLocation));
                if (colIdx != (m_view.Columns.Count - 1))
                {
                    headers.Append(" ");   // separator
                }
            }
            // Clear the header color:
            headers.Append(sm_pop);

            headers.AppendLine();

            // Write -------:
            for (int colIdx = 0; colIdx < m_view.Columns.Count; colIdx++)
            {
                Column c   = m_view.Columns[colIdx];
                int    len = CaStringUtil.Length(c.Label);
                headers.Append(PadAndAlign(new String('-', Math.Min(len, c.CalculatedWidth)),
                                           c.CalculatedWidth,
                                           c.CalculatedAlignment,
                                           c.TrimLocation));
                if (colIdx != (m_view.Columns.Count - 1))
                {
                    headers.Append(" ");   // separator
                }
            }
            SafeWriteObject(headers);
        } // end _WriteHeaders()
Example #3
0
        private ColorString FormatRGB(uint numColumns, bool withAlpha)
        {
            var   bytes        = Memory.Bytes;
            bool  is32Bit      = Debugger.TargetIs32Bit;
            ulong startAddress = Memory.StartAddress;

            if (0 == numColumns)
            {
                numColumns = 64;
            }

            ColorString cs = new ColorString();

            var bytesPerCharacter = withAlpha ? 4 : 3;
            int bytesPerRow       = (int)numColumns * bytesPerCharacter + 3 & ~(3); //round up

            for (int rowStart = 0; rowStart + bytesPerCharacter < bytes.Count; rowStart += bytesPerRow)
            {
                if (rowStart != 0)
                {
                    cs.AppendLine();
                }
                cs.Append(DbgProvider.FormatAddress(startAddress + (uint)rowStart, is32Bit, true, true)).Append("  ");

                var rowLen = Math.Min(bytes.Count - rowStart, bytesPerRow);

                for (int colOffset = 0; colOffset + bytesPerCharacter < rowLen; colOffset += bytesPerCharacter)
                {
                    byte   b  = bytes[rowStart + colOffset + 0];
                    byte   g  = bytes[rowStart + colOffset + 1];
                    byte   r  = bytes[rowStart + colOffset + 2];
                    string ch = "█";
                    if (withAlpha)
                    {
                        ch = AlphaChars[bytes[rowStart + colOffset + 3] >> 6];
                    }
                    cs.AppendFgRgb(r, g, b, ch);
                }
            }

            return(cs.MakeReadOnly());
        }
Example #4
0
        } // end ProcessRecord()

        private void _UnassembleInstructions(ulong addr, Func <ulong, bool> keepGoing)
        {
            ColorString csBlockId;

            try
            {
                ulong disp;
                var   addrName = Debugger.GetNameByOffset(addr, out disp);
                csBlockId = DbgProvider.ColorizeSymbol(addrName);
                if (0 != disp)
                {
                    csBlockId.Append(Util.Sprintf("+{0:x}", disp));
                }
            }
            catch (DbgEngException)
            {
                // Ignore. We'll just use the address as the block id. If we really can't
                // get the memory there, we'll fail with a good error message later.
                csBlockId = new ColorString().Append(DbgProvider.FormatAddress(addr,
                                                                               Debugger.TargetIs32Bit,
                                                                               true));
            }

            csBlockId.Append(":").MakeReadOnly();

            bool hasCodeBytes = !Debugger.AssemblyOptions.HasFlag(DbgAssemblyOptions.NoCodeBytes);

            while (keepGoing(addr))
            {
                ulong  tmpAddr = addr;
                string disasm  = Debugger.Disassemble(tmpAddr, out addr).Trim();
                WriteObject(_ParseDisassembly(tmpAddr,
                                              disasm,
                                              csBlockId,
                                              hasCodeBytes));
            }
            DbgProvider.SetAutoRepeatCommand(Util.Sprintf("{0} -Address 0x{1} -InstructionCount {2}",
                                                          MyInvocation.InvocationName,
                                                          addr.ToString("x"),
                                                          InstructionCount));
            NextAddrToDisassemble = addr;
        } // end _UnassembleInstructions()
        } // end EndProcessing()

        protected override void ApplyViewToInputObject()
        {
            if (!m_calculatedWidths)
            {
                m_view.CalculateWidthsAndAlignments(Host.UI.RawUI.BufferSize.Width, InputObject);
                m_calculatedWidths = true;
            }

            if (!m_headerShown && !HideTableHeaders)
            {
                _WriteHeaders();
                m_headerShown = true;
            }

            // Write row values:
            ColorString row = new ColorString();

            for (int colIdx = 0; colIdx < m_view.Columns.Count; colIdx++)
            {
                if (Stopping)
                {
                    break;
                }

                string val;
                Column c = m_view.Columns[colIdx];
                if (c is PropertyColumn)
                {
                    PropertyColumn pc = (PropertyColumn)c;
                    val = RenderPropertyValue(InputObject, pc.PropertyName, pc.FormatString);
                }
                else
                {
                    ScriptColumn sc = (ScriptColumn)c;
                    val = RenderScriptValue(InputObject, sc.Script);
                    if (null == val)
                    {
                        val = String.Empty;
                    }
                }

                try
                {
                    val = PadAndAlign(val,
                                      c.CalculatedWidth,
                                      c.CalculatedAlignment,
                                      c.TrimLocation);
                }
                catch (Exception e)
                {
                    // Debugging aid to help you figure out what blew up:
                    e.Data["ColumnLabel"] = c.Label;
                    e.Data["val"]         = val;

                    // Sometimes you have a column that's very small (3 or less cells
                    // wide). If you get an error trying to render the value that goes in
                    // it, it will certainly be too wide, but we can't add an ellipsis
                    // when truncating (not enough room). Rather than blow up the
                    // formatting operation, we'll substitute a shorthand to indicate that
                    // an error occurred.
                    if ((e is ArgumentException) && (c.CalculatedWidth <= 3))
                    {
                        if (c.CalculatedWidth == 3)
                        {
                            val = new ColorString(ConsoleColor.Red, "ERR").ToString(DbgProvider.HostSupportsColor);
                        }
                        else if (c.CalculatedWidth == 2)
                        {
                            val = new ColorString(ConsoleColor.Red, "ER").ToString(DbgProvider.HostSupportsColor);
                        }
                        else if (c.CalculatedWidth == 1)
                        {
                            val = new ColorString(ConsoleColor.Red, "X").ToString(DbgProvider.HostSupportsColor);
                        }
                        else
                        {
                            var msg = Util.Sprintf("Calculated width of 0 or less? {0}", c.CalculatedWidth);
                            Util.Fail(msg);
                            throw new Exception(msg, e);
                        }
                    }
                    else
                    {
                        throw;
                    }
                }

                row.Append(val);

                if (colIdx != (m_view.Columns.Count - 1))
                {
                    row.Append(" ");   // separator
                }
            }
            SafeWriteObject(row);
        } // end ApplyViewToInputObject()
Example #6
0
        // Throws a DbgProviderException if the disassembly represents a bad memory access.
        internal static DbgDisassembly _ParseDisassembly(ulong address,
                                                         string s,
                                                         ColorString blockId,
                                                         bool hasCodeBytes)
        {
            // Example inputs:
            //
            //    0113162e 55              push    ebp
            //    0113162f 8bec            mov     ebp,esp
            //    01131631 51              push    ecx
            //    01131632 894dfc          mov     dword ptr [ebp-4],ecx
            //    01131635 8b45fc          mov     eax,dword ptr [ebp-4]
            //    01131638 c70068c81301    mov     dword ptr [eax],offset TestNativeConsoleApp!VirtualBase1::`vftable' (0113c868)
            //    0113163e 8b4508          mov     eax,dword ptr [ebp+8]
            //    01131641 83e001          and     eax,1
            //    01131644 740a            je      TestNativeConsoleApp!VirtualBase1::`scalar deleting destructor'+0x22 (01131650)
            //    01131646 ff75fc          push    dword ptr [ebp-4]
            //    01131649 ff1578c01301    call    dword ptr [TestNativeConsoleApp!_imp_??3YAXPAXZ (0113c078)]
            //    0113164f 59              pop     ecx
            //    01131650 8b45fc          mov     eax,dword ptr [ebp-4]
            //    01131653 c9              leave
            //    01131654 c20400          ret     4
            //
            // Here's what it looks like if the address is bad:
            //
            //    00007ff6`ece87d60 ??              ???
            //

            ColorString cs = new ColorString();

            byte[] codeBytes   = null;
            string instruction = null;
            string arguments   = null;

            Regex goodRegex;
            Regex badRegex;

            if (hasCodeBytes)
            {
                goodRegex = sm_asmRegex;
                badRegex  = sm_badAsmRegex;
            }
            else
            {
                goodRegex = sm_asmRegex_noCodeBytes;
                badRegex  = sm_badAsmRegex_noCodeBytes;
            }

            int matchCount = 0;

            foreach (Match match in goodRegex.Matches(s))
            {
                if (0 == address)
                {
                    // Then we need to parse it out. (this is for -WholeFunction.
                    if (!DbgProvider.TryParseHexOrDecimalNumber(match.Groups["addr"].Value, out address))
                    {
                        throw new Exception(Util.Sprintf("Couldn't convert to address: {0}", match.Groups["addr"].Value));
                    }
                }
#if DEBUG
                else
                {
                    ulong parsedAddress;
                    if (!DbgProvider.TryParseHexOrDecimalNumber(match.Groups["addr"].Value, out parsedAddress))
                    {
                        throw new Exception(Util.Sprintf("Couldn't convert to address: {0}", match.Groups["addr"].Value));
                    }

                    // Nope: these are routinely different on ARM/THUMB2, where the low
                    // bit of the program counter is used as some sort of flag.
                    //Util.Assert( address == parsedAddress );
                }
#endif

                if (hasCodeBytes)
                {
                    codeBytes = Util.ConvertToBytes(match.Groups["codebytes"].Value);
                }

                instruction = match.Groups["instr"].Value;
                arguments   = match.Groups["args"].Value;

                matchCount++;
                cs.AppendPushPopFg(ConsoleColor.DarkCyan, match.Groups["addr"].Value)
                .Append(match.Groups["space1"].Value);

                if (hasCodeBytes)
                {
                    cs.AppendPushPopFg(ConsoleColor.DarkGray, match.Groups["codebytes"].Value)
                    .Append(match.Groups["space2"].Value);
                }

                var instr = match.Groups["instr"].Value;
                cs.Append(DbgProvider.ColorizeInstruction(instr));

                cs.Append(match.Groups["space3"].Value);
                cs.Append(match.Groups["args"].Value);
            }

            if (0 == matchCount)
            {
                var match = badRegex.Match(s);
                if ((null != match) && match.Success)
                {
                    string addrString = match.Groups["addr"].Value;
                    if (0 == address)
                    {
                        if (!DbgProvider.TryParseHexOrDecimalNumber(addrString, out address))
                        {
                            Util.Fail(Util.Sprintf("Couldn't convert to address: {0}", addrString));
                        }
                    }

                    throw new DbgMemoryAccessException(address,
                                                       Util.Sprintf("No code found at {0}.",
                                                                    addrString));
                }
                else
                {
                    throw new Exception(Util.Sprintf("TODO: Need to handle disassembly format: {0}", s));
                }
            }
            else
            {
                Util.Assert(1 == matchCount);
            }

            return(new DbgDisassembly(address,
                                      codeBytes,
                                      instruction,
                                      arguments,
                                      blockId,
                                      cs.MakeReadOnly()));
        } // end _ParseDisassembly()