I have a problem where I can't seem to step into some functions using GDB.
I'm using the "PImpl idiom", where I have an inline class in my .cpp file, containing functions that get called from the publicly visible class, like so:
// Foo.cpp
class FooImpl
{
public:
void open()
{
// ...
}
};
Foo::open()
{
// Impl is a FooImpl*
impl->open();
}
Using the debugger, I can't seem to step into FooImpl::open().
I know for sure that the call is not inlined (I'm using -fno-inline and I can see the call instruction in the assembly);
I can set a breakpoint inside the function and GDB can hit that breakpoint and tell me its name and what function I'm in.
However, it will not tell me the source file (even though it's the same file as Foo::open())
I can't step INSIDE the function; when I execute step, it simply steps over the call.
This is what my stacktrace looks like when I'm on a breakpoint inside the FooImpl::open() call:
#0 0x080eee52 in macawi::PowerMateInputImpl::open(std::string) ()
#1 0x080ee766 in macawi::PowerMateInput::open (this=0x83cf204)
at ../../app/hal/interfaces/powermateinput_linux.cpp:126
#2 0x08137455 in macawi::ActorInput::backgroundLoop (this=0x83cf204)
at ../../app/common/actors/actorinput.cpp:51
Can anyone tell me why GDB can't determine the source location of the top stack frame, even though it's in the same file as stack frame #1?
(For the record, I'm using a graphical debugger that uses GDB in the background (Qt Creator), but the same things hold when I execute GDB directly).
EDIT: The compilation command line looks like this:
g++ -c -pipe -g -O0 -fno-inline -ggdb -fPIC -Wall -W ...(defines, include dirs, object file, source file)
Can anyone tell me why GDB can't determine the source location of the top stack frame, even though it's in the same file as stack frame #1
This is a bug, either in GDB, or in GCC.
Unfortunately, you haven't told us which versions of GCC and GDB you are using, so we can't even begin to guess which versions you may need to update to.
Try building current GDB and GCC. If they still fail, write a small reproducer and file a bug with GDB (if it turns out to be a GCC bug, GDB developers will tell you).
Related
I am having a strange issue with GCC (4.6.4, Ubuntu 12.04) sometimes, I am using it to compile a huge project (hundreds of files and hundreds of thousands of lines of code), but I recently spotted something. After certain compiles (seems to happen randomly), I get a specific piece of code compiled differently and erroneously, causing undefined behavior in my code:
class someDerivedClass : public someBaseClass
{
public:
struct anotherDerived : public anoterBaseClass
{
void SomeMethod()
{
someMember->someSetter(2);
}
}
}
Where "someSetter" is defined as:
void someSetter(varType varName) { someOtherMember = varName; }
Normally, SomeMethod() gets compiled to:
00000000019fd910 mov 0x20(%rdi),%rax
00000000019fd914 movl $0x2,0x278c(%rax)
00000000019fd91e retq
But sometimes it gets (wrongfully) compiled to:
000000000196e4ee mov 0x20(%rdi),%rax
000000000196e4f2 movl $0x2,0x27d4(%rax)
000000000196e4fc retq
The setter seems to get inlined, probably because of compile flags -O2:
-std=c++11 -m64 -O2 -ggdb3 -pipe -Wliteral-suffix -fpermissive -fno-fast-math -fno-strength-reduce -fno-delete-null-pointer-checks -fno-strict-aliasing
but that's not the issue. The real issue is the offset of the member someOtherMember, 0x278c is correct (first case) but 0x27d4 is incorrect (second case) and this obviously ends up modifying a totally different member of the class. Why is this happening? What am I missing? (also, I don't know what other relevant info I can post, so ask). Please keep in mind that this happens when compiling the project again (either full recompile or just compiling modified files only), without modifying the affected file (or files with the used classes). For example, just adding a simple printf() somewhere in a totally unrelated file might trigger this behavior or make it go away when it happens.
Should I simply blame this on the -O2? I can't reproduce it without optimization flag because this happens totally random.
I am using make -j 8, this happens even after cleaning build folder, but doesn't necessarily happen only after doing that
As stated in the comments, you probably have something that conditions the definition of your class differently in the various .cpp, for example a #pragma pack or something like that before the inclusion of your .h; when the linker has to choose, it may choose non-deterministically (since it expects all the definitions to be the same).
To narrow your search for the root of the problem, I would do something like this:
compile your whole project with debug symbols (-g);
use gdb to determine what is the offset of the "problematic" field according to each module
once you find where you have different values, you may use gcc -E to expand all the preprocessor stuff and look for your problem.
As an aid for step 2, you can use this bash one-liner (to be run in the directory where are the object files):
for i in ./*.o; do echo -n "$i: "; gdb -batch -q "$i" -ex "print &((YourClass*)0)->yourField"; done
I am working on implementing a user level thread library in C++ using setcontext(), makecontext(), getcontext(), and swapcontext() on a Linux system.
I am using a wrapper function to wrap the function the user wants to run as a thread. For example, the user calls newthread(funcPtr), and within the thread library funcPtr is passed to a wrapper function that runs it.
The error occurs differently depending on whether or not I initiate an unused string within the function. If I include the line string s = "a"; the program will run to completion, but gdb reveals that context is switching to somewhere within the string library. Without this line, the program segfaults after leaving the function wrapper.
The gdb output shows the corruption of the parameters to function().
I ran valgrind but did not see anything particularly out of the ordinary in the output, just many "Invalid read of size 4" and "Invalid write of size 4" warnings, usually within the C++ standard map.
You could try also AddressSanitizer for debugging. It can detect stack buffer overflows. Here's how to use it on Linux:
At least gcc 4.8 is needed for AddressSanitizer and libasan must be installed (e.g. on Fedora yum install libasan as root). Compile and link with -g -fsanitize=address and run the generated executable. AddressSanitizer stops and emits information if it detects the first error, no long log files have to be analyzed. Solve the reported problem, compile and run again until AddressSanitizer doesn't stop the program anymore. Unfortunately there might be false positives because you use swapcontext in your program, but it's worth a try. Instrumentation can be turned off for a specific function by adding the attribute no_sanitize_address: extern int func(void) __attribute__((no_sanitize_address));
I'm trying to debug some code coming from the Crypto++ library, but I'm getting non-sensical information during the session.
The function of interest is DEREncodePrivateKey. Its a member function on DL_PrivateKey_EC<T> (Crypto++ is heavily templated).
228 pk.DEREncodePrivateKey(encoder);
(gdb) s
non-virtual thunk to CryptoPP::DL_PrivateKey_EC<CryptoPP::ECP>::DEREncodePrivateKey(CryptoPP::BufferedTransformation&) const
(this=0x7fff5fbfeca0, bt=#0x7fff5fbfe540) at dll.cpp:690
Line number 690 out of range; dll.cpp has 146 lines.
dll.cpp can be found at trunk / c5 / dll.cpp, and it only has 146 lines ad gdb reported.
The object was dynamic_cast just before the line in question:
const PKCS8PrivateKey& pk = dynamic_cast<const PKCS8PrivateKey&>(key);
I built the library from sources with -O0 -g3, so I think I minimized some/ most of the typical problems.
I've tried building the library and my test programs with different compilers (g++ and clang++), and I've tried debugging it with different debuggers (gdb and lldb). But I still get the non-sensical information and the library cannot be stepped in this area. Other areas are OK (as can be seen before the issue).
I'm also certain that I'm using my version of the library. Its being linked as a static lib using the full path to the library, and info shared confirms Apple is not sneaking in a dynamic library.
I need to step DL_PrivateKey_EC<CryptoPP::ECP>::DEREncodePrivateKey to see what's going on. I think the function that's being called is in eccrypto, but I'd like to see it under the debugger.
Any ideas how to proceed?
It sounds like the line table in the debug info is incorrect. On Mac OS X you can dump the line table with dwarfdump --debug-line appname.dSYM or if you are looking at a specific object file, dwarfdump --debug-line dll.o. From within lldb you can also do target modules dump line-table dll.cpp. My guess is that some function from a header file was inlined into your dll.cpp -- from line 690 -- but the linetable may incorrectly forget to switch from dll.cpp to your header file.
It seems unlikely that you would see the same problem from both g++ and from clang++. I suspect at least part of your project was not rebuilt.
fwiw you can continue debugging here -- the only problem is that the debugger won't be showing you the source as you step through your method. But you can continue to step and I expect you'll be back in your dll.cpp sources again in no time.
I am using g++ 4.1.2 and gdb 7.2
I am debugging code that uses Xerces, which I built using the same tools, though presumably without debugging.
GDB steps through my code just fine, but of course does NOT step through Xerces because it probably doesn't have debugging information, and definitely does not know where the source directory is. But all I want is to set a breakpoint when Xerces (a callback parser) calls a callback object.
Their base class is DefaultHandler
I have a class ContentHandlerBase : public DefaultHandler
Then leaf classes inherit from ContentHandlerBase. These leaf classes are inside namespace A, for example
in gdb I try to set a breakpoint.
b A::LeafContentHandler::LeafContentHandler
b A::LeafContentHandler::endElement
The first breakpoint works because the code is inline (defined in the header).
The second breakpoint does not work, meaning gdb claims that no such symbol exists, even though it obviously does. It is a virtual function defined in the Xerces library, if that makes a difference. Before I recompiled Xerces, it was built with g++3.4.6 and I could not find the symbol in gdb. Now, gdb finds the symbol (I can hit tab) but then it says it doesn't exist, should I wait for a library to load.
Can anyone tell me what I have to do to make it work? I'd prefer not to build all of xerces with debugging.
Note that in some cases, with the constructor in the .cpp file, it also worked for some reason, and then, because it was in the same file, I could set a subsequent breakpoint at linenumber, and that worked.
Try gdb 7.1 - it seems there are some problems in setting breakpoint by function name in gdb 7.2
Is there a way to inspect object file generated from code below ( file1.o ) for presence of compiler introduced temporary? What tools can we use to obtain such info from object files?
//file1.cpp
void func(const int& num){}
int main(){ func(2); }
The easiest way I can think of to do this is to load up a program that uses the object file and disassemble the function in the debugger. The program code you posted would work fine for this. Just break on the call to func and then display the assembler when you single-step into the function.
In a more complex program you can usually display the assembler code for a given function by name. Check your debugger documentation for how to do this. On Windows (Visual Studio) you can open the Disassembly window and enter the name of the function to display the assembler code.
If you have the source, most compilers allow you to output assembler, sometimes mixed with the source code. For Visual C++ this is /Fa.
If you're on an ELF system and have GNU binutils you can call readelf, probably with the -s switch.
If you have the source available, it is probably easier to look at the assembler file generated by the compiler (-save-temps for gcc). Otherwise, objdump is your friend.
You can use clang -cc1 --ast-print-xml to get a XML representation of a translation unit. The presence of temporaries can be easily detected from the AST.