List Info

Thread: How to call operator<< functions?




How to call operator<< functions?
user name
2006-08-30 10:11:43
Hello,

I have searched the web for an answer without success. The
following 
problem does not seem to exist. Either my configuration is
broken in a 
unique way or my requirements are considered weird and
outrageous (so no 
one tries to do similar things). Read on and tell me what
you think.

I have a complex data structure MyClass (e.g. a parse tree)
which I want 
to examine in GDB. It is impractical to traverse and print
it node by 
node from GDB. For that  I have  written both
MyClass::Print(ostream&) 
and operator<< that invokes this Print. These method
and operator can 
print the data structure in a very nice and readable form. I
can use 
them to print the data into some stream when my application
operates in 
verbose mode.

Now I want to invoke the  operator<<(ostream& ,
MyClass const &) function,
or alternatively the MyClass::Print(ostream&) const --
from GDB;

This does not work even with gcb-6.5, not to mention older
versions. The 
compiler RedHat's gcc-3.4.

Passing 'std::cout' seems impossible. Any attempt to pass
std::cout 
crashes. To overcome this I define my own global
    ostream gecLog(cout.rdbuf()); 
(or something similar) and recompile the code. This lets me
pass gecLog 
instead of cout, and it _sometimes_ works:

(gdb) p pd.Print(gecLog)
Cannot resolve method (null)Print to any overloaded instance
-----------
Now, going through function pointers helps for some weird
reason:

(gdb) p pd.Print
$13 = &MyClass::Print(std::ostream&) const
(gdb) p $13(&pd, gecLog)
Enter Print()
(gdb) p $15(&pd, std::cout)

Program received signal SIGSEGV, Segmentation fault.
0x0042cf88 in std::ostream::sentry::sentry () from
/usr/lib/libstdc++.so.6
The program being debugged was signaled while in a function
called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal
on"
Evaluation of the expression containing the function 
(MyClass::Print(std::ostream&) const) will be abandoned.

--------------------------------------
I wanted to do the same for operator<<:
(gdb) p 'operator<<(std::ostream&, MyClass
const&)'
$17 = {ostream &(ostream &, const class MyClass
     &)} 0x8068a00
<operator<<(std::ostream&, MyClass
const&)>
(gdb) p $17(gecLog, *pd)
Program received signal SIGSEGV, Segmentation fault.
-----------------------

Now, I wanted to write a GDB macro to call Print for me.
When I try to use
  p $-1(&pd, gecLog)
I get a SIGSEGV (when with p $14(....) it would
"just" work).
---------------------

Is there any way to overcome any of the above problems? All
I want is to 
pass a stream such as cerr/cout/clog to a printing function,
is that 
unreasonable?

Thanks
   Michael

P.S.
To overcome this, I am writing a method MyClass:ebugPrin
t() that calls 
Print(cerr). Sometimes, while debugging a piece of code, 
that a vital 
object has <<, but no DebugPrint, and *that* really
frustrates me - 
especially when I loose a 60 minutes debugging session to a
SIGSEGV.
How to call operator<< functions?
user name
2006-08-30 11:12:53
On Wed, 2006-08-30 at 13:11 +0300, Michael Veksler wrote:
> Passing 'std::cout' seems impossible. Any attempt to
pass std::cout 
> crashes. To overcome this I define my own global
>     ostream gecLog(cout.rdbuf()); 
> (or something similar) and recompile the code. This
lets me pass gecLog 
> instead of cout, and it _sometimes_ works:

Just to reply to this little part. 
I've already encountered the issue with cout. In my case
the _ZSt4cout
symbol was present in the debugged binary and (obviously) in
libstdc++.
I _think_ that GDB resolved _ZSt4cout as if the symbol in
the library
was used whereas the one in the executable was the right
one. I can't
remember the reasons for this right now.

As a workaround, I passed '*(ostream*)<addr>' in
place of std::cout. I
found <addr> using nm on my binary. This seemed to
work if I remember
well. It's been a while though...

Hope this helps,
Fred.

How to call operator<< functions?
user name
2006-08-30 12:46:40
As a general note: the most useful thing to accompany any
bug report is
a test case!   We can't
fix them without tests.

On Wed, Aug 30, 2006 at 01:11:43PM +0300, Michael Veksler
wrote:
> Passing 'std::cout' seems impossible. Any attempt to
pass std::cout 
> crashes. To overcome this I define my own global
>    ostream gecLog(cout.rdbuf()); 
> (or something similar) and recompile the code. This
lets me pass gecLog 
> instead of cout, and it _sometimes_ works:

Fred's response seems reasonable; that might be the
problem, or it
might be something else.  If you have a testcase, please
post it.

> (gdb) p pd.Print(gecLog)
> Cannot resolve method (null)Print to any overloaded
instance

Ditto.  I've never seen this error before.

> --------------------------------------
> I wanted to do the same for operator<<:
> (gdb) p 'operator<<(std::ostream&, MyClass
const&)'
> $17 = {ostream &(ostream &, const class MyClass
>     &)} 0x8068a00
<operator<<(std::ostream&, MyClass
const&)>
> (gdb) p $17(gecLog, *pd)
> Program received signal SIGSEGV, Segmentation fault.
> -----------------------

You can just use "print gecLog << *pd". 
Does that work better? 
Anyway, I would have expected calling the operator to work.

With tests for these bugs we can make the next GDB release
the
best ever for C++.

> Print(cerr). Sometimes, while debugging a piece of
code,  that a vital 
> object has <<, but no DebugPrint, and *that*
really frustrates me - 
> especially when I loose a 60 minutes debugging session
to a SIGSEGV.

You might want to use set unwindonsignal, then, as it
suggests. 
There's some risk associated, but it usually works.  You
can also
use "return" to get out of the called function,
but make sure you tell
GDB not to pass the sigsegv when you continue.

-- 
Daniel Jacobowitz
CodeSourcery
How to call operator<< functions?
user name
2006-08-30 13:30:08
On Wed, 2006-08-30 at 13:12 +0200, Frederic RISS wrote:
> I've already encountered the issue with cout. In my
case the _ZSt4cout
> symbol was present in the debugged binary and
(obviously) in libstdc++.
> I _think_ that GDB resolved _ZSt4cout as if the symbol
in the library
> was used whereas the one in the executable was the
right one. I can't
> remember the reasons for this right now.

I digged an old testcase out. Very simple:

-----------------------------8<--------------------------
---------
#include <iostream>

void dump (std::ostream& os)
{
        os << "Hello, guys!" <<
std::endl;
}

int main ()
{
        std::cout << "&std::cout is "
<< &std::cout << std::endl;
        dump (std::cout);
        return 0;
}
-----------------------------8<--------------------------
---------

With neither of the toolcahins I tried (all x86, gcc 4.0 and
4.1 with
recent binutils) I could get the correct value for
&std::cout:

rf23crx549 ~/tmp/cout % gdb --silent a.out
Using host libthread_db library
"/lib/tls/libthread_db.so.1".
(gdb) start
Breakpoint 1 at 0x8048703: file cout.cc, line 11.
Starting program: /home/rf23/tmp/cout/a.out
main () at cout.cc:11
11              std::cout << "&std::cout is
" << &std::cout << std::endl;
(gdb) n
&std::cout is 0x8049a78
12              dump (std::cout);
(gdb) p &std::cout
$1 = (ostream *) 0x582b40
p dump (std::cout)

Program received signal SIGSEGV, Segmentation fault.


As you can see, we get the wrong address. Thus we fail to
pass the right
object when calling a function. Little (re-)investigation
showed that
this is related to symbol versionning. In the static symtab
the
std::cout symbol is versioned and is recorded as such in
GDB's minsym
table:

rf23crx549 ~/tmp/cout % nm a.out| grep cout
49:08049a78 B _ZSt4coutGLIBCXX_3.4
rf23crx549 ~/tmp/cout % nm -D a.out| grep cout
11:08049a78 B _ZSt4cout

This can be confirmed from within GDB:
(gdb) p &'_ZSt4coutGLIBCXX_3.4'
$2 = (<data variable, no debug info> *) 0x8049a78

I don't know how we should handle that. Trimming the symbol
versions
seems wrong (and scanning each symbol for  has a
cost). Maybe we
shouldn't skip the dynamic symtab for the main executable?
Not sure if
it'll solve all such cases.

Fred.



Breakpoint Handling in GDB
user name
2006-08-30 13:40:21
Hello
I was going through the gdb internals on software breakpoint
handling
and have a question regarding that.
Gdb replaces the program instruction with a trap which means
target does
not have any control over setting a bp.
What happens if the connection with the gdb breaks down ? 
Does it mean that the illegal instruction won't be restored
and the
application will crash ?
If that's the case, then how can it be handled ? 


Thanx
Veenu
How to call operator<< functions?
user name
2006-08-30 20:05:43
Daniel Jacobowitz wrote:
> As a general note: the most useful thing to accompany
any bug report is
> a test case!   We can't
fix them without tests.
>   
You are right. At the end of this mail there is a complete
test case for 
about 50% of the reported problems. I'll have to work
harder for a 
simple test case for the other 50%.
> On Wed, Aug 30, 2006 at 01:11:43PM +0300, Michael
Veksler wrote:
>   
>> I wanted to do the same for operator<<:
>> (gdb) p 'operator<<(std::ostream&,
MyClass const&)'
>> $17 = {ostream &(ostream &, const class
MyClass
>>     &)} 0x8068a00
<operator<<(std::ostream&, MyClass
const&)>
>> (gdb) p $17(gecLog, *pd)
>> Program received signal SIGSEGV, Segmentation
fault.
>>     
> You can just use "print gecLog <<
*pd".  Does that work better? 
> Anyway, I would have expected calling the operator to
work.
>
>   
Does not work, look at my complete report below.
> With tests for these bugs we can make the next GDB
release the
> best ever for C++.
>   
Would be great.
>> Print(cerr). Sometimes, while debugging a piece of
code,  that a vital 
>> object has <<, but no DebugPrint, and *that*
really frustrates me - 
>> especially when I loose a 60 minutes debugging
session to a SIGSEGV.
>>     
>
> You might want to use set unwindonsignal, then, as it
suggests. 
> There's some risk associated, but it usually works. 
You can also
> use "return" to get out of the called
function, but make sure you tell
> GDB not to pass the sigsegv when you continue.
>
>   
Thanks this might help 95% of the time.
In some cases I get std::bad_alloc uncaught exception during
Print 
(again, when it should have worked). I doubt that these 5%
of crashes 
can be recovered from. Not a big deal, as it is only about
5..10%.

The complete test case is comprised of c++ source file
(compiled with 
RHEL4's gcc-3.4 using "g++ -g "), and of screen
trace.

Should I open a PR, or several PRs?
Maybe someone else that can split my single test case into
subtopics, 
each to fit its own PR?
Does it make sense to create test case for the missing 50%
of the 
crashes I have seen, or will it be better to wait and see if
they get 
fixed by other PRs?
===================
=> cat cout-gdb.cpp
#include <iostream>

using namespace std;
ostream myCout(cout.rdbuf());

struct A
{
virtual void Print(ostream &out) const = 0;
};

struct B : public A
{
virtual void Print(ostream &out) const
{ out << "Enter B::Print() this=" <<
this << endl; }
};

ostream & operator<<(ostream & out, const
A& data)
{
data.Print(out);
}
int main()
{
B x;
const A & ref_x = x;
ref_x.Print(myCout);

return 0;
}
=> gdb-6.5 -silent a.out
Using host libthread_db library
"/lib/tls/libthread_db.so.1".
(gdb) b 27
Breakpoint 1 at 0x8048a26: file cout-gdb.cpp, line 27.
(gdb) r
Starting program: /home/veksler/a.out
Enter B::Print() this=0xbfffec00

Breakpoint 1, main () at cout-gdb.cpp:27
27 return 0;
(gdb) p x.Print(myCout)

Program received signal SIGSEGV, Segmentation fault.
0x0042cf88 in std::ostream::sentry::sentry () from
/usr/lib/libstdc++.so.6
The program being debugged was signaled while in a function
called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal
on"
Evaluation of the expression containing the function 
(B::Print(std::ostream&) const) will be abandoned.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/veksler/a.out
Enter B::Print() this=0xbfffec00

Breakpoint 1, main () at cout-gdb.cpp:27
27 return 0;
(gdb) p ref_x.Print(myCout)

Program received signal SIGSEGV, Segmentation fault.
0x0042cf88 in std::ostream::sentry::sentry () from
/usr/lib/libstdc++.so.6
The program being debugged was signaled while in a function
called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal
on"
Evaluation of the expression containing the function 
(B::Print(std::ostream&) const) will be abandoned.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/veksler/a.out
Enter B::Print() this=0xbfffec00

Breakpoint 1, main () at cout-gdb.cpp:27
27 return 0;
(gdb) p ref_x.Print
Cannot take address of method Print.
(gdb) p x.Print
$1 = &B::Print(std::ostream&) const
(gdb) p $1(&x, myCout)
Enter B::Print() this=0xbfffec00
$2 = void
(gdb) set $a=x.Print
(gdb) p $a(&x, myCout)

Program received signal SIGSEGV, Segmentation fault.
0x08527e78 in ?? ()
The program being debugged was signaled while in a function
called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal
on"
Evaluation of the expression containing the function (at
0x8527e78) will 
be abandoned.
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/veksler/a.out
Enter B::Print() this=0xbfffec00

Breakpoint 1, main () at cout-gdb.cpp:27
27 return 0;
(gdb) p myCout << x
Structure has no component named operator<<.
(gdb) p 'operator<<(std::ostream&, A
const&)' (myCout, x)
Enter B::Print() this=0xbfffec00
$3 = (ostream &) 0x8049260: <incomplete type>
<<<<<< The above sometimes won't work
(will be reproduced later) >>>>
(gdb) p &'_ZSt4coutGLIBCXX_3.4'
$4 = (<data variable, no debug info> *) 0x8049160
(gdb) p &std::cout
$5 = (ostream *) 0x47cfc0
(gdb) p x.Print
$6 = &B::Print(std::ostream&) const
(gdb) p $6(&x, '_ZSt4coutGLIBCXX_3.4')
Enter B::Print() this=0xbfffec00
$7 = void
(gdb) p $6(&x, std::cout)

Program received signal SIGSEGV, Segmentation fault.

How to call operator<< functions?
user name
2006-08-30 20:23:52
On Wed, Aug 30, 2006 at 11:05:43PM +0300, Michael Veksler
wrote:
> Should I open a PR, or several PRs?
> Maybe someone else that can split my single test case
into subtopics, 
> each to fit its own PR?
> Does it make sense to create test case for the missing
50% of the 
> crashes I have seen, or will it be better to wait and
see if they get 
> fixed by other PRs?

Let's look at one thing at a time.

The first two crashes should, I think, be addressed by this
patch. 
Could you try it?

Some of the later crashes are caused by this:

(gdb) set $a = x.Print
(gdb) p $a
$7 = <error reading variable>

I have a whole lot of patches related to member functions,
that I
haven't had time to merge yet - and I would not like to
look at this
until I've done that.

-- 
Daniel Jacobowitz
CodeSourcery

2006-08-30  Daniel Jacobowitz  <dancodesourcery.com>

	* infcall.c (call_function_by_hand): Check for function
pointer
	types.

Index: src/gdb/infcall.c
============================================================
=======
--- src.orig/gdb/infcall.c	2006-08-30 16:19:00.000000000
-0400
+++ src/gdb/infcall.c	2006-08-30 16:18:43.000000000 -0400
 -337,6
+337,9  call_function_by_hand (struct value *fun
   struct cleanup *caller_regcache_cleanup;
   struct frame_id dummy_id;
 
+  if (TYPE_CODE (ftype) == TYPE_CODE_PTR)
+    ftype = check_typedef (TYPE_TARGET_TYPE (ftype));
+
   if (!target_has_execution)
     noprocess ();
 
Breakpoint Handling in GDB
user name
2006-08-30 20:29:59
On Wed, 2006-08-30 at 15:40 +0200, Veenu Verma (AS/EAB)
wrote:
> Hello
> I was going through the gdb internals on software
breakpoint handling
> and have a question regarding that.
> Gdb replaces the program instruction with a trap which
means target does
> not have any control over setting a bp.
> What happens if the connection with the gdb breaks down
? 
> Does it mean that the illegal instruction won't be
restored and the
> application will crash ?

In the general case, yes, that's what it means.

> If that's the case, then how can it be handled ? 

The newer z0/Z0 remote commands will allow the target debug
agent
(eg. gdbserver) to handle the breakpoints.  But if you're
using the
original method of breakpointing by writing trap
instructions into
target memory, then yes, you're vulnerable to the scenario
that you
describe.

If you can't reboot the target, you MIGHT try re-connecting
with
gdb, and "fixing" the trap instructions by hand.
 Obviously this 
is "at your own risk".  GDB does not have any
built-in capability
to help with the situation that you describe.

However, I *have* used the following method:

1) If possible, get the locations of the breakpoints using
gdb's "info break" command.
2) WITHOUT reconnecting to the target, load the target's 
executable file into gdb, and examine (and record) the
contents 
of memory at those locations, eg. like this:
	(gdb) print /x *(unsigned int *) 0xabcdef

3) Now reconnect to the target, and modify those locations
to match what's in the original binary file, eg.:
	(gdb) set *(unsigned int *) 0xabcdef = <value>

Again, YMMV, use at your own risk, operators are trained 
professionals etc. etc.

Remember, there may be trap instructions that you don't
know about, 
eg. if you were in the middle of a "next" or
"finish" when you lost
communication with the target.


How to call operator<< functions?
user name
2006-08-30 20:45:33
Daniel Jacobowitz wrote:
> On Wed, Aug 30, 2006 at 11:05:43PM +0300, Michael
Veksler wrote:
>   
> Let's look at one thing at a time.
>
> The first two crashes should, I think, be addressed by
this patch. 
> Could you try it?
>   
With the patch it works:

    (gdb) p x.Print(myCout)
    Enter B::Print() this=0xbfffec00
    $1 = void
    (gdb) p ref_x.Print(myCout)
    Enter B::Print() this=0xbfffec00
    $2 = void

Great progress. The most annoying and common failures I have
used to be 
seeing is no more.
The other annoying issues sorted by decreasing annoyance :
- this->Print is not always found (I'll try to create a
small test-case 
later).
- std::cout related crashes
- print myCout << x --- won't work need to resort to
print 'operator<<........'(myCout, x)

> Some of the later crashes are caused by this:
>
> (gdb) set $a = x.Print
> (gdb) p $a
> $7 = <error reading variable>
>
> I have a whole lot of patches related to member
functions, that I
> haven't had time to merge yet - and I would not like
to look at this
> until I've done that.
>
>   
This is less critical since this was an attempt to overcome
the other bug.


Thanks,

Michael
How to call operator<< functions?
user name
2006-08-30 20:54:21
On Wed, Aug 30, 2006 at 11:45:33PM +0300, Michael Veksler
wrote:
> Great progress. The most annoying and common failures I
have used to be 
> seeing is no more.

I will test and commit the patch (but not right this
moment).

> The other annoying issues sorted by decreasing
annoyance :
> - this->Print is not always found (I'll try to
create a small test-case 
> later).

I think my other changes will help here, though I'm not
sure.

> - std::cout related crashes

Fred's pegged this one I suspect.  This is a serious bug
and we need to
fix it, but it will be a bit tricky.

> - print myCout << x --- won't work need to
resort to
> print 'operator<<........'(myCout, x)

I think that foo::operator<< is supported, but
operator<<(foo&,...)
isn't.  Or else something's wrong with the support.

-- 
Daniel Jacobowitz
CodeSourcery
[1-10] [11-20] [21-22]

about | contact  Other archives ( Real Estate discussion Medical topics )