Re: Pb when calling a nested function in the inferior

Joel Brobecker
2001-08-23T03:40:00Z

Hi,

I'm back on this issue I raised sometime ago: gdb calling a nested
subprogram.

> > OK, I'll have a look and see what can be done. But before doing
> > anything, is there a way for gdb to detect that the function it is about
> > to call is nested? I think that, as a first step, having gdb diagnose
> > such cases and report a warning or an error would be an improvement.
> > Right now, it gives either an incorrect value or even crashes the
> > inferior.

A few suggestions were made:

> 1) In the version of gcc that I'm using the symbol that's associated
> with get_value() is get_value.0. You could look for such symbols
> and refuse to allow them to be called as inferior functions.

I originally indicated my preference for this solution, but after
thinking a bit more about it, I don't think this will work, because
languages like C++ or Ada allow overloading. I don't know about the
convention used in C++, but in Ada with GNAT the name of the associated
symbol is made of the name of the subprogram with a suffix such as "__2"
for instance. I guess C++ does more or less the same.

> 2) You could scan the prologue and look for a sequence of instructions
> which looks like a save of the static chain. E.g, in your example,
> I see:
>
> 0x804842c <get_value.0>: push %ebp
> 0x804842d <get_value.0+1>: mov %esp,%ebp
> 0x804842f <get_value.0+3>: sub $0x4,%esp
> 0x8048432 <get_value.0+6>: mov %ecx,0xfffffffc(%ebp)
> 0x8048435 <get_value.0+9>: mov 0xfffffffc(%ebp),%ecx
> 0x8048438 <get_value.0+12>: mov %ecx,%ecx
> 0x804843a <get_value.0+14>: mov 0xfffffffc(%ecx),%eax
> 0x804843d <get_value.0+17>: mov %eax,%eax
> 0x804843f <get_value.0+19>: leave
> 0x8048440 <get_value.0+20>: ret
>
> It appears to me that ``mov %ecx,0xfffffffc(%ebp)'' is
> responsible for saving the static chain pointer. If you could
> detect this, you could print your error or warning. (You'd
> want to make sure that no other instruction with a destination
> of %ecx appears before this instruction in the prologue though;
> if it does, it means it's doing something else.)

I am not sure we really want to go in that direction. For one thing, it
is target dependent, so it will be hard to maintain. Besides, this will
become even more delicate when optimisations are turned on.

With my current limited knowledge of gdb, I came to the conclusion that
the only reliable way of detecting whether the subprogram is nested or
not, and how to set up the call is by having the compiler tell us about
this via the debug information. If there are other ideas that we can
explore, please let me know, I can investigate.

Stabs do not seem to address this issue at all, so I read the DWARF2
specifications.

I don't think the current specifications address completely this
specific issue, but I wanted to discuss this with some of the DWARF2
experts on this list.

I found the DW_AT_static_link attribute that will allow gdb to retrieve
a variable from the outer subprogram when inside the inner subprogram.
This, I think, is a nice flag that can be used to detect nested
subprogram. That would already allow us to perform a good improvement on
gdb, that is to warn a user that he is about to call a nested procedure
which is unsafe (at least for the moment).

On the other hand, there is apparently nothing that tells us that the
static chain needs to be saved in such place by doing such computation.
So we can't go one step further, which is to set up the static chain
before making the call.

A minor point: I tried to compile the small C example with DWARF2 using
a recent gcc snapshot, and got the following debug information:

<<
.byte 0x5 # uleb128 0x5; (DIE (0xa2) DW_TAG_subprogram)
.ascii "get_value\0" # DW_AT_name
.byte 0x1 # DW_AT_decl_file
.byte 0x9 # DW_AT_decl_line
.byte 0x1 # DW_AT_prototyped
.long 0x62 # DW_AT_type
.long .LFB1 # DW_AT_low_pc
.long .LFE1 # DW_AT_high_pc
.byte 0x1 # DW_AT_frame_base
.byte 0x55 # DW_OP_reg5
.byte 0x0 # end of children of DIE 0x69
>>

As far as I can see, gcc does not generate the DW_AT_static_link
attribute yet... Am I reading everything correctly? Should this
attribute be present? If yes, should we discuss this with the gcc folks?

One side question: How do I get the real register corresponding to
DW_OP_reg5? I looked in the gdb sources, and it did not seem obvious to
me. I also looked in the gcc sources, and the result I found looked
suspicious.

Thanks,
--
Joel