static (uint totValid, ulong totBytesValid, uint totInvalid, ulong totBytesInvalid) Gen(Options options, OpCodeInfo[] infos) { var genFlags = InstrGenFlags.None; if (options.UnusedTables) { genFlags |= InstrGenFlags.UnusedTables; } if (!options.OpCodeInfoOptions.IncludeVEX) { genFlags |= InstrGenFlags.NoVEX; } if (!options.OpCodeInfoOptions.IncludeXOP) { genFlags |= InstrGenFlags.NoXOP; } if (!options.OpCodeInfoOptions.IncludeEVEX) { genFlags |= InstrGenFlags.NoEVEX; } if (!options.OpCodeInfoOptions.Include3DNow) { genFlags |= InstrGenFlags.No3DNow; } if (options.OpCodeInfoOptions.Filter.WasRemoved(CpuidFeature.AVX)) { genFlags |= InstrGenFlags.NoAVX; } if (options.OpCodeInfoOptions.Filter.WasRemoved(CpuidFeature.AVX2)) { genFlags |= InstrGenFlags.NoAVX2; } var encodingTables = InstrGen.Create(options.OpCodeInfoOptions.Bitness, infos, genFlags); var instructions = encodingTables.GetOpCodeGroups().SelectMany(a => a.opCodes).SelectMany(a => a.Instructions).Where(instr => { if (!options.Filter.ShouldInclude(instr.Code, instr.IsModrmMemory)) { return(false); } if (instr.Code == Code.INVALID) { return(options.IncludeInvalidInstructions); } return(options.IncludeValidInstructions); }).ToArray(); FileStream? validStream = null; FileStream? invalidStream = null; BinaryWriter?validWriter = null; BinaryWriter?invalidWriter = null; var data2 = new byte[2]; try { if (options.ValidFilename is object) { CreateFile(ref validStream, ref validWriter, options.ValidFilename); } if (options.InvalidFilename is object) { CreateFile(ref invalidStream, ref invalidWriter, options.InvalidFilename); } var fuzzerOptions = FuzzerOptions.NoPAUSE | FuzzerOptions.NoWBNOINVD | FuzzerOptions.NoTZCNT | FuzzerOptions.NoLZCNT; if (options.OpCodeInfoOptions.Filter.FilterEnabled || options.Filter.FilterEnabled) { fuzzerOptions |= FuzzerOptions.NoVerifyInstrs; } if (!options.OpCodeInfoOptions.Filter.WasRemoved(CpuidFeature.MPX)) { fuzzerOptions |= FuzzerOptions.HasMPX; } foreach (var instr in instructions) { switch (instr.Code) { case Code.Pause: fuzzerOptions &= ~FuzzerOptions.NoPAUSE; break; case Code.Wbnoinvd: fuzzerOptions &= ~FuzzerOptions.NoWBNOINVD; break; case Code.Tzcnt_r16_rm16: case Code.Tzcnt_r32_rm32: case Code.Tzcnt_r64_rm64: fuzzerOptions &= ~FuzzerOptions.NoTZCNT; break; case Code.Lzcnt_r16_rm16: case Code.Lzcnt_r32_rm32: case Code.Lzcnt_r64_rm64: fuzzerOptions &= ~FuzzerOptions.NoLZCNT; break; } } var fuzzer = new Fuzzer(options.OpCodeInfoOptions.Bitness, fuzzerOptions, options.OpCodeInfoOptions.CpuDecoder); ulong totBytesValid = 0; ulong totBytesInvalid = 0; uint totValid = 0; uint totInvalid = 0; foreach (var info in fuzzer.GetInstructions(instructions)) { BinaryWriter?writer; bool writeLength; bool writeCodeValue; if (info.Invalid) { totBytesInvalid += (uint)info.EncodedDataLength; totInvalid++; writer = invalidWriter; writeLength = true; writeCodeValue = false; } else { totBytesValid += (uint)info.EncodedDataLength; totValid++; writer = validWriter; writeLength = options.IncludeValidByteLength; writeCodeValue = options.IncludeValidCodeValue; } if (writer is object) { if (writeCodeValue) { uint code = (uint)info.Instruction.Code; if (code > ushort.MaxValue) { throw new InvalidOperationException(); } data2[0] = (byte)code; data2[1] = (byte)(code >> 8); writer.Write(data2, 0, 2); } if (writeLength) { data2[0] = (byte)info.EncodedDataLength; writer.Write(data2, 0, 1); } writer.Write(info.EncodedData, 0, info.EncodedDataLength); } } return(totValid, totBytesValid, totInvalid, totBytesInvalid); } finally { validWriter?.Dispose(); invalidWriter?.Dispose(); validStream?.Dispose(); invalidStream?.Dispose(); } }
static Options ParseOptions(string[] args) { var options = new Options(); var toCpuid = ((CpuidFeature[])Enum.GetValues(typeof(CpuidFeature))).ToDictionary(a => a.ToString(), a => a, StringComparer.OrdinalIgnoreCase); var toCode = ((Code[])Enum.GetValues(typeof(Code))).ToDictionary(a => a.ToString(), a => a, StringComparer.OrdinalIgnoreCase); for (int i = 0; i < args.Length; i++) { var arg = args[i]; var next = i + 1 < args.Length ? args[i + 1] : null; switch (arg) { case "-h": case "--help": throw new CommandLineParserException(string.Empty); case "--quiet": options.Quiet = true; break; case "-16": SetBitness(options, 16); break; case "-32": SetBitness(options, 32); break; case "-64": SetBitness(options, 64); break; case "--show-instructions": options.PrintInstructions = true; break; case "--intel": options.OpCodeInfoOptions.CpuDecoder = CpuDecoder.Intel; break; case "--amd": options.OpCodeInfoOptions.CpuDecoder = CpuDecoder.AMD; break; case "--no-vex": options.OpCodeInfoOptions.IncludeVEX = false; break; case "--no-xop": options.OpCodeInfoOptions.IncludeXOP = false; break; case "--no-evex": options.OpCodeInfoOptions.IncludeEVEX = false; break; case "--no-3dnow": options.OpCodeInfoOptions.Include3DNow = false; options.OpCodeInfoOptions.Filter.ExcludeCode.Add(Code.Femms); options.OpCodeInfoOptions.Filter.ExcludeCpuid.Add(CpuidFeature.CYRIX_D3NOW); break; case "--no-geode-3dnow": options.OpCodeInfoOptions.Filter.ExcludeCpuid.Add(CpuidFeature.CYRIX_D3NOW); break; case "--no-padlock": options.OpCodeInfoOptions.Filter.ExcludeCpuid.Add(CpuidFeature.PADLOCK_ACE); options.OpCodeInfoOptions.Filter.ExcludeCpuid.Add(CpuidFeature.PADLOCK_PHE); options.OpCodeInfoOptions.Filter.ExcludeCpuid.Add(CpuidFeature.PADLOCK_PMM); options.OpCodeInfoOptions.Filter.ExcludeCpuid.Add(CpuidFeature.PADLOCK_RNG); break; case "--no-unused-tables": options.UnusedTables = false; break; case "--include-cpuid": AddCpuid(options.OpCodeInfoOptions.Filter.IncludeCpuid, toCpuid, next); i++; break; case "--exclude-cpuid": AddCpuid(options.OpCodeInfoOptions.Filter.ExcludeCpuid, toCpuid, next); i++; break; case "--include-code": AddCode(options.OpCodeInfoOptions.Filter.IncludeCode, toCode, next); i++; break; case "--exclude-code": AddCode(options.OpCodeInfoOptions.Filter.ExcludeCode, toCode, next); i++; break; case "--gen-include-cpuid": AddCpuid(options.Filter.IncludeCpuid, toCpuid, next); i++; break; case "--gen-exclude-cpuid": AddCpuid(options.Filter.ExcludeCpuid, toCpuid, next); i++; break; case "--gen-include-code": AddCode(options.Filter.IncludeCode, toCode, next); i++; break; case "--gen-exclude-code": AddCode(options.Filter.ExcludeCode, toCode, next); i++; break; case "--no-invalid-instr": options.IncludeInvalidInstructions = false; break; case "--no-valid-instr": options.IncludeValidInstructions = false; break; case "-oil": if (next is null) { throw new CommandLineParserException("Missing filename"); } if (options.ValidFilename is object) { throw new CommandLineParserException("Can't use -oil twice"); } options.InvalidFilename = next; i++; break; case "-ov": AddValidFilename(options, next, false); i++; break; case "-ovl": AddValidFilename(options, next, true); i++; break; case "-ovlc": AddValidFilename(options, next, true); options.IncludeValidCodeValue = true; i++; break; default: throw new CommandLineParserException($"Unknown option {arg}"); } } if (options.OpCodeInfoOptions.Bitness == 0) { throw new CommandLineParserException("Missing bitness: -16 -32 or -64"); } if (!options.PrintInstructions) { if (options.ValidFilename is null && options.InvalidFilename is null) { throw new CommandLineParserException("At least one of -oil, -ovl, -ovlc and -ov must be used"); } } return(options); }
static OpCodeInfo[] GetOpCodeInfos(Options options) => OpCodeInfoProvider.GetOpCodeInfos(options.OpCodeInfoOptions);