/// <summary> /// Seek backward n instructions from a target address /// </summary> /// <param name="address">target address</param> /// <param name="nInstructions">number of instructions</param> /// <returns> address - n on failure, else the address of an instruction n back from the target address</returns> public async Task <ulong> SeekBack(ulong address, int nInstructions) { ICollection <DisasmInstruction> ret = null; ulong defaultAddr = address >= (ulong)nInstructions ? address - (ulong)nInstructions : 0; lock (_disassemlyCache) { // check the cache, look for it to contain nInstructions back from the address var kv = _disassemlyCache.FirstOrDefault((p) => p.Value.TryFetch(address, -nInstructions, out ret)); if (kv.Value != null) { return(ret.First().Addr); } } ulong endAddress; ulong startAddress; var range = await _process.FindValidMemoryRange(address, (uint)(_process.MaxInstructionSize * (nInstructions + 1)), (int)(_process.MaxInstructionSize * -nInstructions)); startAddress = range.Item1; endAddress = range.Item2; if (endAddress - startAddress == 0 || address < startAddress) // bad address range, no instructions { return(defaultAddr); } lock (_disassemlyCache) { // check the cache with the adjusted range var kv = _disassemlyCache.FirstOrDefault((p) => p.Value.TryFetch(startAddress, address < endAddress ? address : endAddress, out ret)); } if (ret == null) { DisasmInstruction[] instructions = await Disassemble(_process, startAddress, endAddress); if (instructions == null) { return(defaultAddr); // unknown error condition } // when seeking back require that the disassembly contain an instruction at the target address (x86 has varying length instructions) instructions = await VerifyDisassembly(instructions, startAddress, endAddress, address); ret = UpdateCache(address, -nInstructions, instructions); if (ret == null) { return(defaultAddr); } } int nLess = ret.Count((i) => i.Addr < address); if (nLess < nInstructions) { // not enough instructions were fetched; back up one byte for each missing instruction return(ret.First().Addr < (ulong)(nInstructions - nLess) ? 0 : (ulong)((long)ret.First().Addr - (nInstructions - nLess))); } else { return(ret.First().Addr); } }