#include "il2cpp-config.h" #include "icalls/mscorlib/System.Diagnostics/StackFrame.h" #include "vm/StackTrace.h" #include "gc/GarbageCollector.h" using namespace mono::vm; namespace mono { namespace icalls { namespace mscorlib { namespace System { namespace Diagnostics { static bool IsCalledFromSystemDiagnosticsStackTrace(const StackFrames& stack) { for (StackFrames::const_iterator frame = stack.begin(); frame != stack.end(); ++frame) if (strcmp(mono_class_get_namespace(mono_unity_method_get_class(frame->method)), "System.Diagnostics") == 0 && strcmp(mono_class_get_name(mono_unity_method_get_class(frame->method)), "StackTrace") == 0) return true; return false; } static bool FrameNeedsSkipped(const MonoStackFrameInfo& frame) { return strcmp(mono_class_get_namespace(mono_unity_method_get_class(frame.method)), "System.Diagnostics") == 0 && (strcmp(mono_class_get_name(mono_unity_method_get_class(frame.method)), "StackFrame") == 0 || strcmp(mono_class_get_name(mono_unity_method_get_class(frame.method)), "StackTrace") == 0); } bool StackFrame::get_frame_info( int32_t skip, bool needFileInfo, MonoReflectionMethod ** method, int32_t* iloffset, int32_t* native_offset, MonoString** file, int32_t* line, int32_t* column) { const int kSkippedFramesFromMSCorlibStackFrameMethods = 2; const int kSkippedFramesFromMSCorlibStackTraceMethods = 2; const StackFrames& stack = *StackTrace::GetStackFrames(); // Always ignore the skipped frames from System.Diagnostics.StackFrame, as we know we are always called from it. // These frames might be inlined or optimized away by the C++ compiler, so we will inspect the actual stack // frames later to see if we need to add skipped frames back in for System.Diagnostics.StackFrame. skip -= kSkippedFramesFromMSCorlibStackFrameMethods; // Sometimes ignore the skipped frames from System.Diagnostics.StackTrace, as we may or may not be called from it. // These frames might be inlined or optimized away by the C++ compiler, so we will inspect the actual stack // frames later to see if we need to add skipped frames back in for System.Diagnostics.StackTrace. if (IsCalledFromSystemDiagnosticsStackTrace(stack)) skip -= kSkippedFramesFromMSCorlibStackTraceMethods; // Now look in the actual stack trace to see if anything we ignored above is really there. We don't know what the C++ // compile will do with these frames, so we need to inspect each frame and check. for (StackFrames::const_iterator frame = stack.begin(); frame != stack.end(); ++frame) { if (FrameNeedsSkipped(*frame)) skip++; } // Finally, find the location in the stack we actually want to use by offsetting from the end of the stack the number of // frames we skipped, and offsetting it by one more to account for this icall itself. int64_t index = stack.size() - skip - 1; if (static_cast(index) >= stack.size() || index < 0) return false; const MonoStackFrameInfo& info = stack[static_cast(index)]; *method = mono_unity_method_get_object(const_cast(info.method)); il2cpp::gc::GarbageCollector::SetWriteBarrier((void**)method); return true; } } /* namespace Diagnostics */ } /* namespace System */ } /* namespace mscorlib */ } /* namespace icalls */ } /* namespace mono */