2009-05-20 4 views
11

리플렉션을 사용할 때 System.Diagnostics.StackTrace를 사용하여 호출 스택을 얻을 수 있습니다 (JIT 최적화로 인해 근사치가 될 수 있음). 포함 된 StackFrame 개체를 검사합니다.스택 프레임에 대해 실행 개체를 얻으려면 어떻게해야합니까?

스택 프레임의 메소드가 실행되고있는 객체 (this-pointer)에 대한 참조를 어떻게 얻을 수 있습니까?

GetMethod() 스택 프레임 개체를 호출하여 MethodBase 가져올 수 있지만 GetObject() (메서드를 정적으로 경우 null 자연스럽게 반환됩니다 찾고 무엇을 찾고 있어요). 스택 프레임 객체는 메서드 정보, 원본 파일 등과 같이 정적으로 결정된 정보에 대해서만 쿼리 할 수있는 것처럼 보입니다.

VS 디버거는 (호출 스택 추적을 얻는 다른 방법을 사용하지만) 호출 스택 창에서 스택 프레임을 두 번 클릭하고 지역 및 클래스 필드의 값을 확인합니다.

편집 : 명확히하기 위해 : 나는 메소드가 호출 된 된 객체 인스턴스를 원한다. I : 메소드 Foo()가 호출 스택의 어딘가에있는 객체 인스턴스 A에서 호출되고 스택 추적을 수행하는 메소드에 계단식으로 연결되면 스택 추적을 수행하는 곳에서 A에 대한 참조를 얻고 싶습니다. (메서드 기반의 선언 형식이 아님)

답변

6

저는 이것이 가능하지 않을 것이라고 확신합니다. 이 유형의 안전을 깰 수

  1. 사람이, 프레임을 조회하는 응용 프로그램 도메인 \ 스레드가에 실행하거나이 권한에 관계없이 객체를 얻을 수 있기 때문에, 왜 여기.

  2. 'this'(C#) 식별자는 실제로는 인스턴스 메서드 (첫 번째)에 대한 인수이므로 정적 메서드와 인스턴스 메서드 사이에는 차이가 없으므로 컴파일러는 올바른 this을 인스턴스 메서드에 추가합니다. 물론 this 개체를 얻으려면 모든 메서드 인수에 액세스해야합니다. 올바른 유형으로 캐스팅 한 후 인스턴스 메서드의 첫 번째 인수의 포인터를 얻을 수 unsafe 코드를 사용하여

그것은 할 수 있습니다 (이 StackFrame는 지원하지 않습니다),하지만 난 방법에 대한 지식이 없다 그것을하기 위해서, 단지 하나의 아이디어.

BTW C# 3.0 확장 메서드처럼 컴파일 된 후에 인스턴스 메서드를 상상해 보면 this 포인터를 첫 번째 인수로 가져옵니다.

+0

이 포인터가 존재하지 않는 GetObject()가 정적 메서드 인 경우 null을 반환하고 인스턴스 메서드에서 표준 'this'포인터의 복사본을 반환하는 이유는 호출자가 호출 스택에서 호출하는 메서드입니다. 그러나 # 1 인수에 동의합니다. 단, 디자인에 따라 적절한 권한을 요구하여 개체에 대한 액세스를 쉽게 제한 할 수 있습니다. –

+0

실제 문제는 StackFrame이 코드에 대한 메타 데이터 일 뿐이며 코드의 라이브 버전이 아니라는 것입니다. – Yona

+0

나는 두려웠다. 그러나 나는 다른 수업이 있기를 바랐다. –

-1

원하는 내용을 완전히 이해하고 있는지 확신 할 수 없지만 특정 스택 프레임에 대한 메서드가 선언 된 형식을 알고 싶다면이 코드

관심이있는 프레임의 색인을 전달해야합니다 (예 : 0을 사용).

+2

그는 유형이 아니라 인스턴스를 의미한다고 생각합니다. –

+0

예, 'object'는 유형의 인스턴스를 의미합니다.) –

+0

네, 사실 깨달았습니다. (질문에 실제로는 분명하며 조금 피곤했습니다 ...) –

3

thiscall 개체에 대한 참조를 얻을 수는 있지만 .NET 코드에서만 사용할 수는 없습니다. 네이티브 코드가 포함되어야합니다. 동적 클래스와 System.Relection.Emit 네임 스페이스를 사용하더라도 .NET에는 다른 메서드 평가 스택 및 인수에 액세스 할 수있는 도구가 없습니다.

다른 방법으로 .NET 메소드를 분해하면이 참조가 실제 스택에 전달되지 않는다는 것을 알 수 있습니다. Thiscall 참조는 ECX (x64의 경우 RCX) 레지스터에 저장됩니다. 따라서 메서드에서 스택에 올라가서 thiscall 개체를 얻고 자하는 메서드로 올라갈 수 있습니다. 그런 다음 스택에있는 레지스터 ECX (RCX)를 저장하는 명령에 대해 해당 메소드의 기계 코드를 조회하고 해당 참조가있는 명령어 상대 주소에서 가져옵니다.

물론 등반 방법은 x32 및 x64 응용 프로그램에서 크게 다릅니다. 이러한 함수를 생성하려면 C#뿐만 아니라 어셈블리 코드를 사용해야하며 x64에서는 인라인 어셈블러가 허용되지 않습니다. 전체 어셈블러 모듈이어야합니다.