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