Forum > Debugger

Debug members of my class kept as interface variable.

(1/2) > >>

tol:
How can I debug members of my class, which is kept as an interface?
With "normal" classes everything seems to work:
For example, I can see the members of a previously constructed object of type TStringList in the local variables window.

But not if I create my own class.
The type of the own class type was derived from


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---type TTest = class(TInterfacedObject, ISomeInterface)
( And instantiated  via a factory class, just in case if that is relevant.  )

The instance is then stored in a variable of type ISomeInterface.

When debugging, I only see the address of the interface in the "local variables" window. None of the members.
The same applies to the list of monitored expressions etc.

I can't see the members via any debugger window. I can't enter an expression that uses a member of the interface either. ("Cannot get member "X" from non-structured type .. ").

How can I debug instances of such classes?

Martin_fr:
Unfortunately there is no way.

Currently FPC does not write any debug info for the interface.

But even if, the interface does only have methods. it does not have a read-able translation into the object that implements it. (Though that would be up to fpc to implement creating such a translation for the debugger/ at least when possible).


Usually an interface has a different implementation for each object that it implements.

If you use asm to step into the call to the interface, then you find code like

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---0000000100001660 4883E920                 sub rcx,$200000000100001664 E997FFFFFF               jmp -$00000069    # $0000000100001600 Foo project1.lpr:210000000100001669 0000                     add [rax],al000000010000166B 0000                     add [rax],al000000010000166D 0000                     add [rax],al000000010000166F 005548                   add [rbp+$48],dl 
The exact code can vary. Or may for other fpc versions be completely different.

The "$20" in the first line is important. But keep in mind that even for the same interface it will vary, depending on the underlaying object that implements that interface.

If you know this value you can watch
  TObject(pointer(MYInterfacei)-$20)

Again, if you run the same code again, but another class is hidden behind the interface then the $20 changes. So you must asm step into the interface each time.


cdbc:
Hi
Remember, there's *always* an object behind an interface, implementing it!
I use interfaces extensively and what I do is this:
1) for properties, I step into the getter/setter, this lands me right smack in
    the implementing object, then I can just hold the mouse over the internal
    fields.
2) for functions/procedures it's pretty much the same, step into and then I
    usually watch local variables...
3) when debugging I 'Log' a lot to screen and file and I keep 'Logging' an
    option via paramstr() in released programs, then I can just start the app
    from the command-line and let it tell me what's wrong...
edit: Try debugging interfaces kept as plugins in libraries ...then you can talk about *Fiddly* :D
HTH
Regards Benny

Martin_fr:
Ok, so now I did take the time...

With my version of FPC 3.2.3, fpc/rtl/project all compiled with -O1
Setting the watch to "use instance type"

--- Code: Text  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---TObject(Pointer(MyInterface)-^byte(((^^^byte(MyInterface)^+3)^)+3)^)
The expression gets the pointer to a function in the interface (the first + 3 is an offset into the internal data - using pointermath, on 64bit that is 24 bytes), and then adds 3. This is the offset to the "20" that is subtracted (in the asm sample of my last post) in the machine code. So if the interface is using a different value (but the same machine code/ compiled with same optimization settings, etc)  then this will find the underlaying object.

tol:
@Martin_fr

Thank you for the time spent on this.
That's what I would have expected, that it would run automatically in the background. (In other languages, debugging the object via one of its interfaces is no problem)

As a "hi-level" developer, I don't really want to (have to) know the internal implementation of the interfaces.
--- Quote from: Martin_fr on May 17, 2024, 07:53:16 pm ---Ok, so now I did take the time...

With my version of FPC 3.2.3, fpc/rtl/project all compiled with -O1
Setting the watch to "use instance type"

--- Code: Text  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---TObject(Pointer(MyInterface)-^byte(((^^^byte(MyInterface)^+3)^)+3)^)
The expression gets the pointer to a function in the interface (the first + 3 is an offset into the internal data - using pointermath, on 64bit that is 24 bytes), and then adds 3. This is the offset to the "20" that is subtracted (in the asm sample of my last post) in the machine code. So if the interface is using a different value (but the same machine code/ compiled with same optimization settings, etc)  then this will find the underlaying object.

--- End quote ---

Navigation

[0] Message Index

[#] Next page

Go to full version