gdb : setting breakpoint when new file is opened or stream instance is created - c++

I have a large code and it is not obvious when it is creating an output file. Is there a way in gdb to put a breakpoint when a new ofstream is created? Or when a file is written to?
I've tried things like
(gdb) b ofstream
Function "ofstream" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) b std::ofstream
Function "std::ofstream" not defined.
Make breakpoint pending on future shared library load? (y or [n]) n
I want to do this so that I can get a backtrace to find out which functions are creating this file.
I also tried
(gdb) catch syscall write
This works except it also catches the output to the screen (and the output to stdout is verbose), when really I want to catch the output to a file.
EDIT: Here is a minimal working example.
#include <iostream>
#include <fstream>
using namespace std;
int main () {
cout << "hello world\n" ;
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}

This works except it also catches the output to the screen
You can exclude output to stdout with conditional breakpoint. On x86_64 this can be done with comparing rdi register to 1:
(gdb) catch syscall write
Catchpoint 1 (syscall 'write' [1])
(gdb) condition 1 $rdi!=1
(gdb) i b
Num Type Disp Enb Address What
1 catchpoint keep y syscall "write"
stop only if $rdi!=1
(gdb)
You can also set conditional breakpoint on exact file descriptor you want. See https://stackoverflow.com/a/8052681/72178 how to map file name to file descriptor on Linux.

Unfortunately you have to provide the complete function prototype. But gdb can give you a list of available methods and functions. If you type (note the single quote)
(gdb) break 'std::
you can invoke the auto-completion with tabulator. This will return a list of all gdb known methods and functions under namespace std. In your case (ofstream) you will find following entry in the list:
std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(char const*, std::_Ios_Openmode)```
Now just set the breakpoint with following command:
(gdb) break std::basic_ofstream<char, std::char_traits<char> >::basic_ofstream(char const*, std::_Ios_Openmode)
run it and it should work as expected.

Related

gdb debugger quits prematurely on popen(), 'signal SIGTRAP, Trace/breakpoint trap'?

The following code works in stand alone (non-debugging) mode. However gdb debugging stops when I tried to step over popen(), meaning a breakpoint at the fgets() can never be reached.
#include <stdio.h>
int main()
{
char buff[10];
FILE *f = popen("echo blah", "r");
// program and debugger exit before this line
// so that fgets() and printf() were never called
fgets(buff, 5, f);
printf("%s\n", buff);
}
GDB reports Program terminated with signal SIGTRAP, Trace/breakpoint trap. I dug into glibc's popen() and this is where it quits,
// internal-signal.h
/* Block all signals, including internal glibc ones. */
static inline void
__libc_signal_block_all (sigset_t *set)
{
INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &sigall_set, set,
__NSIG_BYTES);
}
Does anyone knows what is going on here? thanks!
Turned out to be a kernel issue, at least when I reverted back from 5.15.x to 5.14.x, the issue went away. I thought kernel update were never meant to break userspace.

How do I get more information about that error?

An Qt application is crashing and even debugger mode it's all I get:
ASSERT: "!isEmpty()" in file
C:\Qt\Qt5.5.0\5.5\mingw492_32\include\QtCore/qlist.h, line 321
That line in the file points to:
inline void removeLast() { Q_ASSERT(!isEmpty()); erase(--end()); }
But I'd like more information. Like what line exactly in the source code is using it (from search, no direct call to removeLast() done).
Is this possible?
If you run your program in a debugger, it will stop on the assertion and you'll be able to examine the stack trace. For example with this program in GDB :
#include <QList>
int main(int argc,char* argv[])
{
QList<int> my_list;
my_list.append(1);
my_list.pop_back(); // 1
my_list.pop_back(); // 2
return 0;
}
When you run it :
(gdb) r
Starting program: /home/leiaz/tmp/qttest/build/proj
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
ASSERT: "!isEmpty()" in file /usr/include/qt/QtCore/qlist.h, line 321
Program received signal SIGABRT, Aborted.
0x00007ffff61275f8 in raise () from /usr/lib/libc.so.6
The assertion stop the debugger, and you can ask for the stack trace :
(gdb) backtrace
#0 0x00007ffff61275f8 in raise () from /usr/lib/libc.so.6
#1 0x00007ffff6128a7a in abort () from /usr/lib/libc.so.6
#2 0x00007ffff6dc11e1 in QMessageLogger::fatal(char const*, ...) const () from /usr/lib/libQt5Core.so.5
#3 0x00007ffff6dbc34e in qt_assert(char const*, char const*, int) () from /usr/lib/libQt5Core.so.5
#4 0x00000000004060aa in QList<int>::removeLast (this=0x7fffffffe4d0)
at /usr/include/qt/QtCore/qlist.h:321
#5 0x0000000000405de0 in QList<int>::pop_back (this=0x7fffffffe4d0)
at /usr/include/qt/QtCore/qlist.h:337
#6 0x0000000000405ad4 in main (argc=1, argv=0x7fffffffe5d8) at /home/leiaz/tmp/qttest/main.cc:9
You can see removeLast was called by pop_back and my code start at frame 6 :
(gdb) frame 6
#6 0x0000000000405ad4 in main (argc=1, argv=0x7fffffffe5d8) at /home/leiaz/tmp/qttest/main.cc:9
9 my_list.pop_back(); // 2
Here you can examine the values of other variables in that frame.
If you are using Qt Creator see Viewing Call Stack Trace.
Like what line exactly in the source code is using it (from search, no direct call to removeLast() done). Is this possible?
Unfortunately assert() or Q_ASSERT() macros just show that the conditions were wrong, not which code was causing these conditions.
Especially if called many times and/or from many places, assertions aren't very helpful to detect what code actually was causing it.
You can set a conditional breakpoint for the isEmpty() condition, if that's well supported with your debugger.
You can also set a breakpoint in the standard abort() function, if you have access to the debug symbols.
If there's not, and if you have full access to the source code (which you have for a function inlined in a header) you can work around that deficiency. The way I'm usually going, is to change such code temporarily to
void removeLast()
{
if(isEmpty()) { // <<<<<<<<<<< Put an encapsulating if clause here
return; // <<<<<<<<<<<< set breakpoint
}
Q_ASSERT(!isEmpty()); erase(--end());
}
and set a debugger breakpoint. When the breakpoint is hit while running the code from the debugger, I'll examine the call stack to see where this came from.

debug c++ template with gdb

When I debug inside a function with template,
How do I know which template type the current function is using?
I tried p T. It says gdb cant print a type.
How do I break on a particular template type?
Lets say function foo<T>(...) have 2 possible forms, foo<int>(...) and foo<long>(...) . How do I set a breakpoint so that gdb only pauses on the first one which uses int, but not the second one which uses long?
Edit: It would be nice if the breakpoint can be set by line number. There are many good reasons for this, eg. the initial part of function may take long to run, the place I wish to debug may be inside an if statement etc.
To set a breakpoint to all instances use:
gdb> rbreak Foo<.*>
To only set a breakpoint on a known instance
gdb> break Foo<int>
You can also use rbreak Foo<int> but it makes no sense to use a call witch evaluates regular expressions but you give none :-)
Example Code:
#include <iostream>
#include <string>
template < typename T>
T Foo(T t) { return t; }
int main()
{
std::cout << Foo<int>(1) << std::endl;
std::cout << Foo<std::string>("Hallo") << std::endl;
}
Simply compile with debug info:
g++ main.cpp -g -o go
Run gdb:
gdb go
And test:
gdb> rbreak Foo<int>
gdb> run
gdb> backtrace
gdb> cont
As you can see: Only one instance of the template is affected.
In the backtrace you can see which template instance is called:
#0 Foo<int> (t=1) at main.cpp:5
#1 0x0000000000400b69 in main () at main.cpp:9
As you can see it is Foo<int> here.
To answer a comment:
"Is there a way to place a breakpoint in the specific known instance at a certain line?"
Yes!
gdb> break main:692
gdb> info break
this will return something like
Num Type Disp Enb Address What
5 breakpoint keep y <MULTIPLE>
5.1 y 0x00000000004026db in Foo<int>(int) at main.cpp:692
5.2 y 0x00000000004027a6 in Foo<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) at main.cpp:692
(gdb)
Now you can disable specific instances with:
gdb> disable 5.2
You can not delete a specific "sub breakpoint". But disable is quite what you need. You can also give a range of instances if you like with e.g.:
gdb> disable 5.1-2
You can use ptype rather than p to print a type. With a recent enough (couple of years old) g++ and gdb, this will work.
Consider this source:
#include <iostream>
template<typename T>
struct S
{
S(T t)
{
std::cout << t;
}
};
int main()
{
S<const char*> s2("hello");
S<int> s1(23);
return 0;
}
Here I can step into the constructor for s2 and see T:
(gdb) ptype T
type = const char *
Take a look the current frame:
(gdb) frame
#0 S<char const*>::S (this=0x7fffffffe35f, t=0x400940 "hello") at q.cc:8
8 std::cout << t;
I can set a breakpoint using the function name given there:
(gdb) b S<const char *>::S
Breakpoint 2 at 0x40087a: file q.cc, line 8.

same piece of C++ code works in g++ 4.6 compiler but crashes with 5.1

The following piece of code works with g++ 4.6 compiler but crashes with segmentation fault when compiled with g++ 5.1 compiler. The variable access gString is causing the segmentation fault.
#define _GLIBCXX_DEBUG 1
#define _GLIBCXX_USE_CXX11_ABI 0
#include<string>
#include<iostream>
#include<vector>
static std::string gString("hello");
static void
__attribute__((constructor))
initialize()
{
gString.assign("hello world");
return;
}
static void
__attribute__((destructor))
finalize()
{
return;
}
int main(int ac, char **av)
{
//std::cerr<<gString;
return 0;
}
GDB output:
Reading symbols from /home/rk/str...done.
(gdb) b initialize
Breakpoint 1 at 0x401419: file str.cc, line 15.
(gdb) r
Starting program: /home/rk/str
Breakpoint 1, initialize() () at str.cc:15
15 gString.assign("hello world");
(gdb) n
Program received signal SIGSEGV, Segmentation fault.
0x00000000004018d6 in std::string::size() const () at /usr/include/c++/5/bits/basic_string.h:3118
3118 { return _M_rep()->_M_length; }
(gdb) bt
#0 0x00000000004018d6 in std::string::size() const () at /usr/include/c++/5/bits/basic_string.h:3118
#1 0x00000000004016ff in std::string::assign(char const*, unsigned long) () at /usr/include/c++/5/bits/basic_string.tcc:706
#2 0x000000000040166e in std::string::assign(char const*) () at /usr/include/c++/5/bits/basic_string.h:3542
#3 0x0000000000401428 in initialize() () at str.cc:15
#4 0x00000000004023dd in __libc_csu_init ()
#5 0x00007ffff71ad700 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#6 0x0000000000401289 in _start ()
Why are you using __attribute__((constructor)) in C++ instead of simply a global object with a constructor? Those attributes are useful in C code, but redundant in C++.
The problem is that your constructor runs before the standard iostreams have been initialized, which would not be a problem if you used a global object with a constructor.
You could try adding a priority to your constructor, but I don't think it will help in this case:
__attribute__((constructor(999)))
The runtime error also happens with gcc 4.9.2 (see ideone example).
The problem is related to the iostreams which are not yet initialized. Commenting out the cerr line, and everything works fine
Apparently, it's a known issue.
Edit: Additional remarks
This small workaround seems to work, at least with 4.9: use c stdio instead of iostreams:
fprintf(stderr, "_initialize"); // this works
But I fully agree with Jonathan's suggestion of using a global (singleton ?) object relying solely on well defined standard C++ behaviour, unless you really need the constructor being run exactly at the moment of a dynamic library load.

Setting breakpoint on a class's member function in a file

(gdb) b breakpoints.cpp:X::X()
Can't find member of namespace, class, struct, or union named "breakpoints.cpp:X::X"
Hint: try 'breakpoints.cpp:X::X()<TAB> or 'breakpoints.cpp:X::X()<ESC-?>
(Note leading single quote.)
Make breakpoint pending on future shared library load? (y or [n]) n
on the following code:
#include <stdio.h>
#include <iostream>
class X
{
public:
X ()
{
std :: cout << "\nIn the default constructor";
}
X (int)
{
std :: cout << "\nIn the parameterized constructor";
}
~X () {}
};
int main (int argc, char *argv[])
{
X xObjA;
X xObjB (11);
while (--argc > 0)
{
printf("\n%s ", argv [argc]);
}
std :: cout << std :: endl << std :: endl;
}
File's name is: breakpoints.cpp
What's the point that I am missing?
That is the correct way to set a breakpoint.
You are either trying that on a wrong executable (put breakspoints.cpp in a directory and compile with g++ -g breakpoints.cpp and then use the gdb on the a.out executable), code that is different than posted and maybe having namespaces, or you stumbled on an old bug due to using an outdated gdb version.
Perhaps you need to define your breakpoints without the file name. The following works for me:
break FooNamespace::FooClass::doSomething()
I imagine this only works when the class is unique however, so it should be in a namespace.
Note
If there are multiple places where the breakpoint can be placed, I think gdb will try to place breakpoints on all of the places, so you will end up with something like the following:
Breakpoint 1 at 0x7fe62f8e744d: file src/FooClass.cpp, line 42. (2 locations)
(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
1.1 y 0x00007fe62f8e744d in FooNamespace::FooClass::doSomething() at src/FooClass.cpp:42
1.2 y 0x00007fe62f8e7c5d in FooNamespace::FooClass::doSomething() at src/FooClass.cpp:42
You may need to specify the namespace if any defined for the class. If it other than the standard namespace std.
The file name is optional, if you are executing the correct binary.
You can verify if the symbol exists on the executable via. "nm -C" command, where -C handles name mangling for C++.
So to summarise with an Example:
If the namespace is "mySpace" and the class is "X" whose member is "Y",
then the breakpoint should be like the one below,
"(gdb) b mySpace::X::Y"