Informatics

a sucessful gdb use case

As I was compiling a little program for detecting radiation on my Raspberry Pi, I was obliged to use gdb in order to debug the problem that I was driven to.

After transforming a little program from its Arduino form in order to use it on the RPi (see the necessary hardware here)… well it just blew up and stopped :-o

The original program is the one you can found here.

Arduino code is so similar to C++, that after porting the LiquidCrystal library for making it suitable for compiling on RPi, and making the rest of changes to the code, I forget that in fact things were a little more tricky. The list of changes to the original code is this:

  • predeclare functions (ledVar and countPulse):

void ledVar(int value);
void countPulse();

  • change ‘include <LiquidCrystal.h>’ for ‘include “LiquidCrystal.h”‘, so the include is searched on the local directory… as it has been modified just for this case, I won’t put it on any default system include directory.
  • comment “long time = 0;” as it isn’t used anywhere… and it clashes with C defined “time” variable:

/usr/include/time.h:186:15: error: previous declaration of ‘time_t time(time_t*)’

  • add a main() function:

int main (){
setup();
while(1){
loop();
}
return (0);
}

Here is the ERRONEOUS code in case you wanna play with it and gdb: a-sucessful-gdb-use-case.tgz.

$ g++ -lrt -lpthread arduino_lcd_geiger.ERRONEOUS.c LiquidCrystal.cpp Print.cpp arduPi.cpp -o arduino_lcd_geiger.ERRONEOUS

Well, a quick compile and execute ends with… nothing at all: the program dies. And as it does so without a reason, it must have collapsed with a Segmentation Fault.

But, which and where is the fault?

:-o

The program can be compiled with the “-g” option, so debug information is included in the executable.

$ g++ -g -lrt -lpthread arduino_lcd_geiger.ERRONEOUS.c LiquidCrystal.cpp Print.cpp arduPi.cpp -o arduino_lcd_geiger.ERRONEOUS

Now, gdb can be used to try to track the problem. The minimum set of options to know are:

  • b <function>: set a breakpoint on function
  • run : runs the program. If no breakpoints have been set, it’ll not stop unless some terrible error occurs.
  • backtrace : prints the stack calls made until the actual execution point.
  • p <variable> : prints the value of “variable” on the actual execution point.
  • quit

So a gdb of the program shows:

$ sudo gdb arduino_lcd_geiger.ERRONEOUS
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html&gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type “show copying”
and “show warranty” for details.
This GDB was configured as “arm-linux-gnueabihf”.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>&#8230;
Reading symbols from /home/pi/arduino_lcd_geiger.ERRONEOUS…done.
(gdb) b main
Breakpoint 1 at 0x976c: file arduino_lcd_geiger.ERRONEOUS.c, line 181.
(gdb) run
Starting program: /home/pi/arduino_lcd_geiger.ERRONEOUS
[Thread debugging using libthread_db enabled]
Using host libthread_db library “/lib/arm-linux-gnueabihf/libthread_db.so.1”.

Program received signal SIGSEGV, Segmentation fault.
0x0000e238 in pinMode (pin=23, mode=OUTPUT) at arduPi.cpp:1138
1138                            case 23: GPFSEL2 &= ~(7 << 9);  GPFSEL2 |= (1 << 9);  break;
(gdb) backtrace
#0  0x0000e238 in pinMode (pin=23, mode=OUTPUT) at arduPi.cpp:1138
#1  0x00009b4c in LiquidCrystal::init (this=0x18ce8, fourbitmode=1 ’01’, rs=3 ’03’, rw=255 ‘\377′,
enable=4 ’04’, d0=5 ’05’, d1=6 ’06’, d2=7 ‘\a’, d3=8 ‘\b’, d4=0 ’00’, d5=0 ’00’, d6=0 ’00’,
d7=0 ’00’) at LiquidCrystal.cpp:74
#2  0x00009a84 in LiquidCrystal::LiquidCrystal (this=0x18ce8, rs=3 ’03’, enable=4 ’04’, d0=5 ’05’,
d1=6 ’06’, d2=7 ‘\a’, d3=8 ‘\b’) at LiquidCrystal.cpp:54
#3  0x000097d4 in __static_initialization_and_destruction_0 (__initialize_p=1, __priority=65535)
at arduino_lcd_geiger.ERRONEOUS.c:37
#4  0x000097f8 in _GLOBAL__sub_I_lcd () at arduino_lcd_geiger.ERRONEOUS.c:187
#5  0x0000fc94 in __libc_csu_init ()
#6  0xb6d237b0 in __libc_start_main () from /lib/arm-linux-gnueabihf/libc.so.6
#7  0x0000901c in _start ()
(gdb) p gpio
$1 = {addr_p = 538968064, mem_fd = 0, map = 0x0, addr = 0x0}
(gdb) quit

The stack shows that the problem arises on LiquidCrystal.cpp, after trying to use pinMode fucntion. But pinMode() uses raspberryPinNumber(), which in turn depends on GPFSEL0 variable… which after a quick look into arduPi.h:

#define GPFSEL0    *(gpio.addr + 0)

After printing the variable gpio, we see something strange: it has oxo values, and it should not be the case: this means that it has not been initialized.

The initialization occurs at the end of arduPi.cpp library (it’s quite odd, but I suppose this has been made to resemble as much as possible the Arduino code, which is not C code strictly speaking):

WirePi Wire = WirePi();

This calls the class constructor, which in turn uses WirePi::map_peripheral() to populate gpio values:

map_peripheral(&gpio);

int WirePi::map_peripheral(struct bcm2835_peripheral *p) {

p->mem_fd = open(“/dev/mem”, O_RDWR|O_SYNC)

p->map = mmap(
NULL,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED,
p->mem_fd,  // File descriptor to physical memory virtual file ‘/dev/mem’
p->addr_p      // Address in physical map that we want this memory block to expose
);

So, gpio cannot be “zero”… Unless the constructor hasn’t been called yet when the program tries to use gpio for the first time…

From the debug stack, we see that the guilty use is from “arduino_lcd_geiger.ERRONEOUS.c:37”, line 37… which is the call to the constructor of LiquidCrystal. It is outside any function, so it must happen before even main() is called… but this seems to leave the decision of code order execution before main() on compiler hands… which in this case it does not seem a good idea: let’s call the constructor of LiquidCrystal *inside* main(), so every include has already been executed and this way the problem should disappear.

This modification oblige us to pass a pointer to this local main() object so it can be accessed:

int main (){
// initialize the library with the numbers of the interface pins
// AFTER WirePi has been initialized (!)
LiquidCrystal lcd(3,4,5,6,7,8);
setup(&lcd);
while(1){
loop(&lcd);
}
return (0);
}

This time, this code’s compiled executable…

$ g++ -lrt -lpthread arduino_lcd_geiger.c LiquidCrystal.cpp Print.cpp arduPi.cpp -o arduino_lcd_geiger

will softly run!

And compiled with “-g” and run with gdb, the gpio variable is in fact correctly initialized at the same point where it was “zeroed” before:

(gdb) b main
Breakpoint 1 at 0x9764: file arduino_lcd_geiger.c, line 183.
(gdb) run
Starting program: /home/pi/arduino_lcd_geiger
[Thread debugging using libthread_db enabled]
Using host libthread_db library “/lib/arm-linux-gnueabihf/libthread_db.so.1”.

Breakpoint 1, main () at arduino_lcd_geiger.c:183
179         LiquidCrystal lcd(3,4,5,6,7,8);
(gdb) p gpio
$1 = {addr_p = 538968064, mem_fd = 7, map = 0xb6ff7000, addr = 0xb6ff7000}
(gdb) n
185         setup(&lcd);
(gdb) n
[New Thread 0xb6d0b460 (LWP 14828)]
188             loop(&lcd);
(gdb) quit

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s