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()); }
// 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()