Saturday, November 10, 2007

Using the GNU Debugger

The GNU debugger(gdb) comes standard with any Linux installation(Okay maybe not, but its can be selected during installation).Also, it comes with the Bloodshed Dev-CPP C/CPP IDE for Windows. Its a very useful but often overlooked tool for C/CPP development.Most programmers resort to multiple printfs at various points in the code to trace out the error. This approach seems paleolithic when you see the advantages offered by gdb.
For one thing, the printfs make the code messy.Secondly, debugging is a very painstaking process when using printfs.This comes from personal experience of course.
Also after you are done debugging,you have to cleanup those print statements.
These are just a few reasons.Start using gdb and more will become obvious to you.

Thats why I emphasize the use of gdb.

Now a lot of people have come to me asking me the procedure for using gdb. I guess from now on I can just throw the blog at them

Lets look at the steps involved.
(For Linux only, Bloodshed offers a GUI interface,which is pretty straight forward.If you still want a tute.Leave a comment)

1.Compile with symbol table information

You can use either "cc" or "g++" depending on your language of choice.For the sake of simplicity,we will assume cc for the duration of this discussion.Similar arguments apply to g++.
When compiling use the "-g" option/flag.This allows your program to be debugged by gdb.

Basically, this tells the compiler to store symbol table information (source level symbols) in your
object file or load module.

For example,suppose we are trying to a compile are C source file dfs_ops.c. This file is standalone and does not link with any other object files other than the standard C library.
The Command to execute is

:> cc dfs_ops.c -g -o dfs_ops

This will tell the compiler to compile dfs_ops.c into an executable file dfs_ops and also store the symbol table information in the file.
As is obvious, storing the symbol table in your executable increases its physical size. So make sure you dont do this in your final deliverable.(Which will hopefully be thoroughly tested. :-))

2. Start a debugging session for your program with gdb

Next, you need to enter into a session with gdb, to interactively debug your program with gdb.
This means the program must be started under control of gdb.
To do this you can do either of the following in a shell...

i) :> gdb
In this approach , you start gdb but do not specify any program to debug.In this case you must run a program expicitly from the gdb prompt to start a debugging session.
This can be done as follows.
gdb:> run <program_name>

Here is the name of a program that you want to debug.This could be a full path or just the program name in the current directory.

ii) :> gdb <program_name>

In this approach, you explicitly specify the program which you want to debug.

After you have entered in a session with gdb, you should see a gdb prompt. Similar to this..

gdb:>

3.Setting a breakpoint

Now that you have entered in a session with gdb, using either of the two approaches in step 2, you must set an execution break point.This is a point in the program where the gdb will pause execution and give control to you.You can then perform various actions like looking at variable values,register values, funtion returns,step wise execution etc.
To set a break point, use the "break" command at the gdb prompt.
You can set a break point either by specifying a line number or function name.

gdb:> break <line_num>
gdb:> break <func_name>

Note: Pressing TAB here, will list available functions and class methods

For example :

gdb:> break 80 // Pauses execution at Line 80 w.r.t to the Source file line numbers
gdb:> break main //pause execution when program control enters function main

You can specify multiple break points

More to come...just wait....

Saturday, November 03, 2007

Linux File System Development using FUSE

FUSE (Filesystems in User Space) is an open source project that allows developers to create file systems as user application as against a kernel module (which is the normal case). It is obvious to developers familiar with FS development to notice that ,a filesystem in userspace would mean a significant performance penalty. Certainly there is a performance hit because the filesystem application communicates with the FUSE module which in turn handles VFS communication introducing an extra level of indirection.

So why bother?

FUSE is certainly worth the performance trade-off for a number of reasons :

1.FUSE offers a higher level interface which much simpler than the VFS interface.This forms an excellent starting point for budding file system developers to get the hang of things.
2.FUSE also offers a lower layer interface which is akin to the VFS interface.This allows developers familiar with VFS to test out their File system code in user space before introducing it as a kernel module.Those who know about kernel panics and constant reboots and kernel re-compilation that are part of Linux kernel development will know why this convenience is of such great value.
3.For some file systems where performance is not an issue, developing file systems is not only easier but also a much faster process, because the now the developers have a the whole C library at their disposal which will be linked to their file system application.Means lots of utility functions.

Although, the documentation and tutorials for FUSE are few and far between.And whatever there are, are not easily accessible.So I will try to include a tutorial for FUSE on my blog some time later.No promises..