Как получить исполняемый объект для стекового кадра?

При использовании отражения можно получить стек вызовов (кроме того, что это может быть грубое приближение из-за JIT-оптимизаций) с использованием System.Diagnostics.StackTrace и изучить содержащиеся в нем объекты StackFrame.

Как получить ссылку на объект (указатель this), над которым выполняется метод в кадре стека?

Я знаю, что могу получить MethodBase, вызвав GetMethod() для объекта стекового фрейма, но я ищу что-то похожее на GetObject() (который, естественно, возвращает null, если метод статический). Кажется, что объект стекового фрейма может быть запрошен только для статически определенной информации, такой как информация о методе, исходный файл и т. Д.

Отладчик VS знает (хотя он, вероятно, использует другой метод получения трассировки стека вызовов), поскольку можно дважды щелкнуть любой кадр стека в окне стека вызовов и посмотреть значения локальных переменных и полей класса.

РЕДАКТИРОВАТЬ: Чтобы уточнить: я хочу экземпляр объекта, на котором был вызван метод. То есть: если метод Foo() вызывается для экземпляра объекта A где-нибудь в стеке вызовов, и он каскадно относится к методу, который я выполняю трассировку стека, я хотел бы получить ссылку на A, откуда я выполняю трассировку стека. (Не объявляемый тип базы метода)

3 ответа

Решение

Я уверен, что это невозможно. Вот почему:

  1. Это может нарушить безопасность типов, так как любой может искать кадр, получать объект независимо от того, для какого AppDomain\Thread он выполняется или какого разрешения он имеет.

  2. 'thisИдентификатор ' (C#) на самом деле является просто аргументом для метода экземпляра (первого), поэтому в действительности нет никакой разницы между статическими методами и методами экземпляра, компилятор делает все возможное, чтобы передать правильный this к методу экземпляра, что, конечно, означает, что вам нужно будет иметь доступ ко всем аргументам метода, чтобы получить this объект. (который StackFrame не поддерживается)

Это может быть возможно с помощью unsafe код, чтобы получить указатель первого аргумента на метод экземпляра и затем привести его к нужному типу, но я не знаю, как это сделать, просто идея.

Кстати, вы можете представить методы экземпляра после компиляции как методы расширения C# 3.0, они получают this указатель в качестве первого аргумента.

Можно получить ссылку на thiscall объект, но не только с кодом.NET. Родной код должен быть вовлечен. Даже с использованием динамических классов и пространства имен System.Relection.Emit.NET не имеет инструментов для доступа к стеку и аргументам оценки других методов.

С другой стороны, если вы разберете свой метод.NET, вы увидите, что эта ссылка вообще не передается в физический стек. Thiscall ссылка хранится в ECX(RCX для х64) зарегистрируйтесь вместо. Таким образом, можно подняться по стеку от вашего метода к методу, из которого вы хотите получить thiscall объект. А затем ищите внутри машинных кодов этого метода инструкции, которые сохраняют регистр ECX (RCX) в стеке, и получаете от адреса этой инструкции, где находится эта ссылка.

Конечно, метод лазания сильно отличается в приложениях x32 и x64. Для создания такой функции вы должны использовать не только C#, но и ассемблерный код, и помнить, что встроенный ассемблер не разрешен в x64; это должен быть полный модуль ассемблера.

Я не уверен, что полностью понимаю, что вы хотите, но если вы хотите знать тип, в котором объявлен метод для определенного стекового фрейма, я думаю, что этот код возвращает следующее:

StackTrace trace = new StackTrace();    
Type methodOwner = trace.GetFrame(0).GetMethod().DeclaringType;

Вам, конечно, нужно будет передать индекс для кадра, который вас интересует (я использую 0 в качестве примера).

Другие вопросы по тегам