private static void WriteStackObjects(ClrRuntime runtime, ClrThread thread, TextWriter output) { var heap = runtime.Heap; var start = thread.StackBase; var stop = thread.StackLimit; if (start > stop) { Util.Swap(ref start, ref stop); } output.WriteLine("Stack objects:"); for (var ptr = start; ptr <= stop; ptr += (ulong)runtime.PointerSize) { if (!runtime.ReadPointer(ptr, out var obj)) { break; } var type = heap.GetObjectType(obj); if (type == null) { continue; } if (type.IsFree) { continue; } output.WriteLine("{0,16:X} {1,16:X} {2}", ptr, obj, type.Name); } }
public ulong ReadPointer(ulong Address) { StartRuntime(); ulong ptr; m_runtime.ReadPointer(Address, out ptr); return(ptr); }
private static void DumpStack(ClrRuntime runtime, ClrThread thread) { // We'll need heap data to find objects on the stack. var heap = runtime.Heap; // Walk each pointer aligned address on the stack. Note that StackBase/StackLimit // is exactly what they are in the TEB. This means StackBase > StackLimit on AMD64. var start = thread.StackBase; var stop = thread.StackLimit; // We'll walk these in pointer order. if (start > stop) { var tmp = start; start = stop; stop = tmp; } Log.Information("Stack objects:"); // Walk each pointer aligned address. Ptr is a stack address. for (var ptr = start; ptr <= stop; ptr += (ulong)runtime.PointerSize) { // Read the value of this pointer. If we fail to read the memory, break. The // stack region should be in the crash dump. if (!runtime.ReadPointer(ptr, out var obj)) { break; } // We check to see if this address is a valid object by simply calling // GetObjectType. If that returns null, it's not an object. var type = heap.GetObjectType(obj); if (type == null) { continue; } // Don't print out free objects as there tends to be a lot of them on // the stack. if (type.IsFree) { continue; } Log.Information("{pointer,16:X} {object,16:X} {typeName}", ptr, obj, type.Name); try { WriteFields(obj, type); } catch (Exception e) { Log.Error("Failed to write values"); } } }
private static List <string> GetStackObjects(ClrRuntime runtime, ClrThread thread) { var stackObjects = new List <string>(); var heap = runtime.Heap; // Walk each pointer aligned address on the stack. Note that StackBase/StackLimit // is exactly what they are in the TEB. This means StackBase > StackLimit on AMD64. var start = thread.StackBase; var stop = thread.StackLimit; // We'll walk these in pointer order. if (start > stop) { var tmp = start; start = stop; stop = tmp; } // Walk each pointer aligned address. Ptr is a stack address. for (var ptr = start; ptr <= stop; ptr += (ulong)runtime.PointerSize) { // Read the value of this pointer. If we fail to read the memory, break. The // stack region should be in the crash dump. if (runtime.ReadPointer(ptr, out var obj) == false) { break; } // 003DF2A4 // We check to see if this address is a valid object by simply calling // GetObjectType. If that returns null, it's not an object. var type = heap.GetObjectType(obj); if (type == null) { continue; } // Don't print out free objects as there tends to be a lot of them on // the stack. if (type.IsFree) { continue; } stackObjects.Add(type.Name); } return(stackObjects); }
public override bool TryGetSymbolCore(ulong address, out SymbolResolverResult result) { const ulong MIN_ADDR = 0x10000; if (address < MIN_ADDR) { result = default; return(false); } string name; name = clrRuntime.GetJitHelperFunctionName(address); if (!(name is null)) { result = new SymbolResolverResult(SymbolKind.Function, name, address); return(true); } name = clrRuntime.GetMethodTableName(address); if (!(name is null)) { result = new SymbolResolverResult(SymbolKind.Data, "methodtable(" + name + ")", address); return(true); } var method = clrRuntime.GetMethodByAddress(address); if (method is null && (address & ((uint)clrRuntime.PointerSize - 1)) == 0) { if (clrRuntime.ReadPointer(address, out ulong newAddress) && newAddress >= MIN_ADDR) { method = clrRuntime.GetMethodByAddress(newAddress); } } if (!(method is null)) { result = new SymbolResolverResult(SymbolKind.Function, method.ToString(), address); return(true); } result = default; return(false); }
public override bool TryGetSymbolCore(ulong address, out SymbolResolverResult result) { string name; name = clrRuntime.GetJitHelperFunctionName(address); if (name != null) { result = new SymbolResolverResult(SymbolKind.Function, name, address); return(true); } name = clrRuntime.GetMethodTableName(address); if (name != null) { result = new SymbolResolverResult(SymbolKind.Data, "methodtable(" + name + ")", address); return(true); } var method = clrRuntime.GetMethodByAddress(address); if (method == null && address >= 0x10000) { if (clrRuntime.ReadPointer(address, out ulong newAddress)) { method = clrRuntime.GetMethodByAddress(newAddress); } } if (method != null) { result = new SymbolResolverResult(SymbolKind.Function, method.ToString(), method.NativeCode); return(true); } result = default; return(false); }
static void Main(string[] args) { string dump = string.Empty, dac = string.Empty; bool dso = false; int pid = Convert.ToInt32(args[0]); //if (!TryParseArgs(args, out dump, out dac, out dso)) //{ // Usage(); // return; //} ClrRuntime runtime = CreateRuntime(pid, dump, dac); // Walk each thread in the process. foreach (ClrThread thread in runtime.Threads) { // The ClrRuntime.Threads will also report threads which have recently died, but their // underlying datastructures have not yet been cleaned up. This can potentially be // useful in debugging (!threads displays this information with XXX displayed for their // OS thread id). You cannot walk the stack of these threads though, so we skip them // here. if (!thread.IsAlive) { continue; } Console.WriteLine("Thread {0:X}:", thread.OSThreadId); Console.WriteLine("Stack: {0:X} - {1:X}", thread.StackBase, thread.StackLimit); // Each thread tracks a "last thrown exception". This is the exception object which // !threads prints. If that exception object is present, we will display some basic // exception data here. Note that you can get the stack trace of the exception with // ClrHeapException.StackTrace (we don't do that here). ClrException exception = thread.CurrentException; if (exception != null) { Console.WriteLine("Exception: {0:X} ({1}), HRESULT={2:X}", exception.Address, exception.Type.Name, exception.HResult); } // Walk the stack of the thread and print output similar to !ClrStack. Console.WriteLine(); Console.WriteLine("Managed Callstack:"); foreach (ClrStackFrame frame in thread.StackTrace) { // Note that CLRStackFrame currently only has three pieces of data: stack pointer, // instruction pointer, and frame name (which comes from ToString). Future // versions of this API will allow you to get the type/function/module of the // method (instead of just the name). This is not yet implemented. Console.WriteLine("{0,16:X} {1,16:X} {2}", frame.StackPointer, frame.InstructionPointer, frame.DisplayString); } // Print a !DumpStackObjects equivalent. if (dso) { // We'll need heap data to find objects on the stack. ClrHeap heap = runtime.Heap; // Walk each pointer aligned address on the stack. Note that StackBase/StackLimit // is exactly what they are in the TEB. This means StackBase > StackLimit on AMD64. ulong start = thread.StackBase; ulong stop = thread.StackLimit; // We'll walk these in pointer order. if (start > stop) { ulong tmp = start; start = stop; stop = tmp; } Console.WriteLine(); Console.WriteLine("Stack objects:"); // Walk each pointer aligned address. Ptr is a stack address. for (ulong ptr = start; ptr <= stop; ptr += (ulong)runtime.PointerSize) { // Read the value of this pointer. If we fail to read the memory, break. The // stack region should be in the crash dump. ulong obj; if (!runtime.ReadPointer(ptr, out obj)) { break; } // 003DF2A4 // We check to see if this address is a valid object by simply calling // GetObjectType. If that returns null, it's not an object. ClrType type = heap.GetObjectType(obj); if (type == null) { continue; } // Don't print out free objects as there tends to be a lot of them on // the stack. if (!type.IsFree) { Console.WriteLine("{0,16:X} {1,16:X} {2}", ptr, obj, type.Name); } } } Console.WriteLine(); Console.WriteLine("----------------------------------"); Console.WriteLine(); } }
public int ReadPtr(ulong addr, out ulong pValue) { bool success = m_runtime.ReadPointer(addr, out pValue); return(success ? 1 : 0); }
/// <summary> /// Reads a pointer value out of the target process. This function reads only the target's pointer size, /// so if this is used on an x86 target, only 4 bytes is read and written to val. /// </summary> /// <param name="address">The address to read from.</param> /// <param name="value">The value at that address.</param> /// <returns>True if the read was successful, false otherwise.</returns> /// <inheritdoc /> public bool ReadPointer(ulong address, out ulong value) => Runtime.ReadPointer(address, out value);
private bool GetReferencedAddressToMethodName(out ulong refAddress, out uint codeSize, out string name, Instruction instruction, ClrRuntime runtime) { name = null; refAddress = 0; codeSize = 0; bool isAddressOk = false; for (int i = 0; i < instruction.OpCount; i++) { switch (instruction.GetOpKind(i)) { case OpKind.NearBranch16: case OpKind.NearBranch32: case OpKind.NearBranch64: refAddress = instruction.NearBranchTarget; isAddressOk = refAddress > ushort.MaxValue; break; case OpKind.Immediate64: refAddress = instruction.GetImmediate(i); isAddressOk = refAddress > ushort.MaxValue; break; case OpKind.Memory64: refAddress = instruction.MemoryAddress64; isAddressOk = refAddress > ushort.MaxValue; break; case OpKind.Memory when instruction.IsIPRelativeMemoryOperand: refAddress = instruction.IPRelativeMemoryAddress; isAddressOk = refAddress > ushort.MaxValue; break; case OpKind.Memory: refAddress = instruction.MemoryDisplacement; isAddressOk = refAddress > ushort.MaxValue; break; } } if (refAddress == 0) { return(false); } var jitHelperFunctionName = runtime.GetJitHelperFunctionName(refAddress); if (string.IsNullOrWhiteSpace(jitHelperFunctionName) == false) { name = jitHelperFunctionName; return(true); } var methodTableName = runtime.GetMethodTableName(refAddress); if (string.IsNullOrWhiteSpace(methodTableName) == false) { name = methodTableName; return(true); } var methodDescriptor = runtime.GetMethodByHandle(refAddress); if (methodDescriptor != null) { name = methodDescriptor.Name; refAddress = methodDescriptor.HotColdInfo.HotStart; codeSize = methodDescriptor.HotColdInfo.HotSize; return(true); } var methodCall = runtime.GetMethodByAddress(refAddress); if (methodCall != null && string.IsNullOrWhiteSpace(methodCall.Name) == false) { name = methodCall.Name; refAddress = methodCall.HotColdInfo.HotStart; codeSize = methodCall.HotColdInfo.HotSize; return(true); } if (methodCall == null) { if (runtime.ReadPointer(refAddress, out ulong newAddress) && newAddress > ushort.MaxValue) { methodCall = runtime.GetMethodByAddress(newAddress); } if (methodCall is null) { return(false); } name = methodCall.Name; refAddress = methodCall.HotColdInfo.HotStart; codeSize = methodCall.HotColdInfo.HotSize; return(true); } return(false); }