Playing with ReturnAddress I discovered that it will be pretty easy to implement retrieval of name of an object's method without any RTTI or debug info. Could be useful for logging. Alas, it relies on class layout internals but that's the only way to do. Code bases on TObject.MethodAddress // Get address of currently executed code function GetCurrentAddress: Pointer; begin Result := ReturnAddress; end; // Get name of class method that contains the given address. // Note that it has to utilize some internals function GetMethodName(AClass: TClass; Address: Pointer): string; overload; type // copy declaration from System's impl section PMethRec = ^MethRec; MethRec = packed record recSize: Word; methAddr: Pointer; nameLen: Byte; { nameChars[nameLen]: AnsiChar } end; var LMethTablePtr: Pointer; LMethCount: Word; LMethEntry, LResultMethEntry: PMethRec; begin Result := ''; { Obtain the method table and count } LMethTablePtr := PPointer(PByte(AClass) + vmtMethodTable)^; if LMethTablePtr = nil then // no methods... Exit; LMethCount := PWord(LMethTablePtr)^; if LMethCount = 0 then // no methods... Exit; Inc(PWord(LMethTablePtr)); // Get all method entries and find max method entry addr that is less (or equal - very unlikely tho) than Address LMethEntry := LMethTablePtr; LResultMethEntry := nil; while LMethCount > 0 do begin // Only consider methods starting before the Address if PByte(LMethEntry.methAddr) <= PByte(Address) then begin // Not assigned yet if (LResultMethEntry = nil) or // Current entry is closer to Address, reassign the variable (PByte(LMethEntry.methAddr) > PByte(LResultMethEntry.methAddr)) then LResultMethEntry := LMethEntry; end; Dec(LMethCount); LMethEntry := Pointer(PByte(LMethEntry) + LMethEntry.recSize); // get next end; if LResultMethEntry <> nil then Result := string(PShortString(@LResultMethEntry.nameLen)^); end; // Get name of object's method that contains the given address function GetMethodName(AObject: TObject; Address: Pointer): string; overload; begin Result := GetMethodName(AObject.ClassType, Address); end; Test cases: program Project2; {$APPTYPE CONSOLE} {$R *.res} type TBaseClass = class procedure method; virtual; end; TTestClass = class(TBaseClass) procedure foo; procedure method; override; procedure method1; inline; procedure bar; class procedure classMethod; end; procedure TBaseClass.method; begin end; procedure TTestClass.method; var s: string; begin Assert(GetMethodName(Self, GetCurrentAddress) = 'method', 'override'); // do some stuff to get another address str(123, s); Assert(GetMethodName(Self, GetCurrentAddress) = 'method', 'override'); end; procedure TTestClass.foo; begin Assert(GetMethodName(Self, GetCurrentAddress) = 'foo', 'usual - 1st'); end; procedure TTestClass.bar; begin Assert(GetMethodName(Self, GetCurrentAddress) = 'bar', 'usual - last'); end; procedure TTestClass.method1; begin Assert(GetMethodName(Self, GetCurrentAddress) <> 'method1', 'inline'); end; class procedure TTestClass.classMethod; begin Assert(GetMethodName(Self, GetCurrentAddress) = 'classMethod', 'class method'); end; var cl: TTestClass; begin cl := TTestClass.Create; cl.foo; cl.method; cl.method1; // ! inlined methods won't be detected ! cl.bar; cl.classMethod; TTestClass.classMethod; Writeln('All tests OK'); readln; end.