Debugging C++ templates is difficult. Debugging C++ templates with GDB can be an act of torture for even seasoned GDB users. I like GDB, but there are some tricks you should know when using it to debug templates. In this post, I deal with setting breakpoints.
Setting a breakpoint in GDB is supposed to be simple. Here we set a breakpoint at line 50 in file main.cpp:
(gdb) b main.cpp:50
Breakpoint 1 at 0x804937a: file main.cpp, line 50.
We can also use the function name and GDB will attempt to find the correct location for us:
(gdb) b DoSomething
Breakpoint 2 at 0×8049334: file main.cpp, line 150
Simple, right? Just wait…
GDB’s breakpoint logic is pretty handy for simple projects, but it can break down fast when things get more complicated.
For example, let’s say your application is plugin-driven, with each plugin being a separate library. Now assume each plugin has a Plugin.cpp file under it’s own Source directory. Try to set a breakpoint in the Initialize() method of the Plugin class:
(gdb) b Initialize
Breakpoint 3 at 0×8049717: file main.cpp, line 230
Oops! There is an Initialize() method in main.cpp and GDB thought that’s where we wanted to put it: wrong!
Recently, I was trying to run a GUI front-end to Valgrind (Valkyrie) from within a chroot’d environment on Fedora 9. It failed to run, and after some searching I figured out the problem. Here’s the story.
First, I made sure to disable access control from outside the chroot (warning: make sure you understand the security implications of this!):
[dev]$ xhost + localhost
localhost being added to access control list
Next, I entered the chroot’d environment and attempted to run the application, but it failed with the following error:
valkyrie: cannot connect to X server 127.0.0.1:0.0
The problem is that the X server is configured by default NOT to listen for remote connections (usually on port 6000). I verified that this was the problem by leaving the chroot and trying to connect via telnet:
[dev]$ telnet 127.0.0.1 6000
telnet: connect to address 127.0.0.1: Connection refused
The way to fix this on previous Fedora installations was to use gdmsetup. However, this is no longer available. Hunting through the KDE config files I found the solution: change the arguments passed to the X server after login in the kdmrc file.
NOTE: I’m using fluxbox as my desktop environment… KDE is used for the Fedora login screen, which is why we are messing with its config files.
[dev]$ sudo su
[root]# cd /etc/kde/kdm
[root]# cp kdmrc kdmrc.old
[root]# vi kdmrc
On my system, the problem was this line:
ServerArgsLocal=-br -nolisten tcp
I simply changed it to:
I restarted my X server and tried to connect with telnet again (this time with success):
[dev]$ telnet 127.0.0.1 6000
Connected to 127.0.0.1.
Escape character is ‘^]’.
Then, I once again disabled X access control (`xhost + localhost`) and everything worked fine. Hope this helps!
EDITED 11/17/2008: Changed ‘xhost +’ to ‘xhost + localhost’
I’m always forgetting how to register my machine name with the DHCP server so I can ping my box without having to remember my IP address. Here’s how to do it on Fedora Core 9:
- Set the hostname: `# hostname <hostname>`
- Add ‘HOSTNAME=<hostname>’ to ‘/etc/sysconfig/network’ (makes the change permanent).
- Add ‘DHCP_HOSTNAME=<hostname>’ to ‘/etc/sysconfig/network-scripts/ifcfg-eth0′
- Restart the networking service: `# service network restart`
Volia! Now you can connect to your box via hostname.
High Scalability has a great link to a video TechTalk with Cuong Do, YouTube’s engineering manager. He talks about the challenges YouTube faces (past and present) to meet it’s skyrocketing user demand, as well as the infrastructure that allows them to scale. I enjoyed the anecdotes: especially the frantic email sent at 2am alerting the dev team that they only had 3 days of storage left… I always thought Google/YouTube would be immune to emergencies like that… ignorance on my part
I found this information interesting:
- The application code is written mostly in Python (the web app is not the bottleneck… the database RPC is)
- They use Apache for page content and lighttpd for serving video
- Thumbnails are now served by Google’s BigTable
- They’re running SuSE Linux with MySQL
- HW RAID-10 across multiple disks was too slow. HW RAID-1 with SW RAID-0 was faster because the Linux I/O scheduler could see the multiple volumes and would therefore schedule more I/O
You can read a good summary of the talk HERE from the High Scalability website.
When writing a shared library, it is sometimes useful to have a set of functions that get called when the library is loaded and unloaded. In Windows, this is done by implementing the DllMain function. This function is called by the loader whenever a DLL is loaded or unloaded into the address space of a process (and also when the process creates a new thread, but it is less common to handle this case). A value is passed in as an argument to the DllMain function that indicates which event is occurring: DLL load or unload.
On Linux, one must use the GCC __attribute__((constructor)) and __attribute__((destructor)) keywords (double underscores before and after) to explicitly declare functions to be called on load and unload. These keywords cause the compiler/linker to add the specified functions to the __CTOR_LIST__ and __DTOR_LIST__ (“ConstrucTOR LIST” and “DestrucTOR LIST” respectively) in the object file. Functions on the __CTOR_LIST__ are called by the loader when the library is loaded (either implicitly or by dlopen()). The main purpose for this list is to call the constructors on global objects in the library. Conversely, functions on the __DTOR_LIST__ are called when the library is unloaded (either implicitly or by dlclose()). By adding initialization and clean-up functions to this list, one can effectively replicate the DllMain functionality on Linux.
NOTE: There are many ways to “shoot yourself in the foot” with these methods (on both Windows and Linux) because certain things aren’t available to your library until loading is complete. Don’t use these methods unless you have a real need… just export an Initialize() and Destroy() function instead, and force the consuming application to call them. Please read the “Gotcha’s” section below.